I want to display a number that increases once every second, rather than using some kind of time function I am using window.setInterval because eventually I will replace this with some more complicated code that instead of just displaying the number calls some function and displays the result. Here is the code I have right now:
export default class Test extends Component {
constructor(props){
super(props)
this.state = {counter:0}
}
render(){
newCounter = this.state.counter+1 // I am going to replace this
// with something like:
// newCounter = someFunc()
func = this.setState
window.setInterval(function(){
func({counter:newCounter})
},1000);
return(
<View>
<Text>{this.state.counter}</Text>
</View>
)
}
}
It gives me this error: undefined is not an object (evaluating 'this.updater')
how can I do this correctly? Thanks
Try this:
export default class Test extends Component {
constructor(props){
super(props)
this.state = {counter:0}
}
componentDidMount(){
setInterval(() => {
this.setState( prevState => ({counter: prevState.counter + 1}));
},1000);
}
render(){
return(
<View>
<Text>{this.state.counter}</Text>
</View>
)
}
}
Basically, you want to use the function arrow with set Interval, to not lose the context of the this keyword, and try to use set State outside of the render method.
Here is a demo as well: https://snack.expo.io/HkikISZMm
Related
Below are 2 patterns of code from a simple react native class component. Is there any performance difference in those? The difference is in the way a function called on an event of native control. If there is a performance difference, I want to know how to check and verify actually there is performance difference.
Pattern 1:-
class MyClass extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
}
}
onNameChange = (text) => {
this.setState({ name: text });
}
render() {
const { name } = this.state;
return (
<TextInput onChangeText={this.onNameChange} value={name} />
)
}
}
Pattern 2:-
class MyClass extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
}
}
onNameChange = (text) => {
this.setState({ name: text });
}
render() {
const { name } = this.state;
return (
<TextInput onChangeText={(text) => {
this.onNameChange(text);
}} value={name} />
)
}
}
If there is a performance difference then I need to adopt to the first pattern.
I think that there is no performance difference since the code gets transformed or minified before it gets executed.
There is no performance difference in the two patterns that you have mentioned.
First one just passes the reference to execute.
Second is just the wrapper (anonymous function) to execute your actual function.
Here is my constructor. When I run the code it throws the following error in React Native 0.61x.
export default class Date extends Component {
static navigationOptions = ({ navigation }) => {
const { params } = navigation.state;
};
constructor(props) {
super(props)
this.state = {
title: null,
day: new Date(),
}
}
render() {
const { navigation } = this.props
return(
<View style={{flex: 1, backgroundColor: 'white'}}>
<Header
navigation={navigation}
icon='back'/>
<Title>{i18n.t('create.date_title')}</Title>
</View>
)
}
}
Unhandled JS Exception: RangeError: Maximum call stack size exceeded
When I comment the code it does not throw the error anymore.
Also, why is StackOverflow so bad at copy pasting code? I am doing something wrong or what cause only a few lines of code get indented as code when I paste them.
Running these features in the creator can cause a lot of renderings.
You can use componentDidMount()
constructor(props) {
super(props);
this.state = {
//defauilt value of the date time
date: '',
};
}
componentDidMount() {
var date = new Date()
that.setState({ date: date });
}
Look at your declaration export default class Date extends Component
You are overwriting Date with your own Component. Try renaming your Component.
I have the following Snack setup (please use Android version):
https://snack.expo.io/#sj458147/stackoverflow-unable-to-call-method
When clicking Go to step 2 - I get undefined is not an object, the View should scroll by calling the method - moveToPage
If a user was to swipe the Modal View, it would move to next the next View. How can I stop this interaction (the view should only scroll when the user clicks a button and not by swiping).
Expo gives the message this.refs is deprecated, how would I update this code?
you need to use React.createRef() in your constructor. And use this reference in your component. In go() function, to achieve moveToPage(2) you need to use current of your reference like in the below;
class ShowModal2 extends Component {
constructor(props){
super(props);
this.MyScrollView = React.createRef();
}
go = () => {
this.MyScrollView.current.moveToPage(2);
};
render() {
return (
<Modal
style={styles.modal}
isVisible={true}
onBackdropPress={this.hideModal}>
<MyScrollView ref={this.MyScrollView}>
......
and apply same approach to other class
class MyScrollView extends Component {
constructor() {
super();
this.state = { page: '' }
this.scrollView = React.createRef();
}
moveToPage(page) {
this.scrollView.current.scrollTo({ x: ((page - 1) * device_width), y: 0,
animated: true });
alert(page);
}
render() {
return (
<View style={styles.container}>
<ScrollView ref={this.scrollView} showsHorizontalScrollIndicator={false} horizontal={true} pagingEnabled={true}>
......
and check from link please-> https://snack.expo.io/#sdkcy/stackoverflow-unable-to-call-method
Working on a cancer treatment app in react native:
Current functionality: when I move the sliders and change the date on my app, it dispatches changes to the redux store successfully. Unfortunately, my UI doesn't update, even though I am calling the same store from the presentational components that I called for dispatch.
That results in this:
GIF of redux store changing while UI is static
Printing via
store.getState();
store.subscribe(() =>
console.log(store.getState())
);
I tried using subscription, but it seems like this isn't the right way to go about this. Thoughts?
snippets from my code (all in one small file, linked below)
Action
//action
function set_num_treatments(num) {
return {
type: SET_NUM_TREATMENTS,
num: num
}
}
setting the title
SET_NUM_TREATMENTS = "SET_NUM_TREATMENTS"
main reducer
function main_reducer(state = initialState, action) {
switch (action.type) {
case SET_PAGE_VIEW:
return Object.assign({}, state, {
current_page: action.page_of_interest
})
case SET_NUM_TREATMENTS:
return Object.assign({}, state, {
num_treatments: action.num
})
case SET_INTER_TREATMENT_INTERVAL:
return Object.assign({}, state, {
inter_treatment_interval: action.weeks_between_treatments
})
case SET_TREATMENT_START_DATE:
return Object.assign({}, state, {
treatment_start_date: action.date
})
default:
return state
}
return state
}
Here's where I start the store & produce the printing functionality
let store = createStore(main_reducer);
store.getState();
store.subscribe(() =>
console.log(store.getState())
);
here's the presentational components
class TreatmentSettings extends React.Component {
constructor(props){
super(props)
}
render() {
const props = this.props
const {store} = props
const state = store.getState()
return(
<View style={styles.treatment_option_slider_card}>
<Text style={styles.my_font, styles.tx_settings_header}>{state.num_treatments} Treatments</Text>
<Slider step={1} minimumValue={1} maximumValue={20} value={12}
onValueChange={(num_treatments) => {store.dispatch(set_num_treatments(num_treatments))}} />
<Text style={styles.my_font, styles.tx_settings_header}>X Weeks Between Treatments</Text>
<Slider step={1} minimumValue={1} maximumValue={4} value={2} style={{marginBottom:60}}
onValueChange={(value) => {store.dispatch(set_inter_treatment_interval(value))}}
/>
</View>
)
}
}
These final two components hold the main containers for the app
export default class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<Provider store={createStore(main_reducer)}>
<AppContainer />
</Provider>
);
}
}
class AppContainer extends React.Component {
constructor(props){
super(props)
}
render(){
return(
<View style={styles.container}>
<TreatmentSettings store={store} />
<Text>footertext</Text>
</View>
)
}
}
the one gist file is here if you want to see it all: https://github.com/briancohn/learning-redux/blob/navigation_addn/App.js
I really appreciate the help—
Thanks in advance!
-Brian
I think the way you are updating the store is fine but there’s something wrong with how your components are listening to the changes.
It seems you meant to use connect from react-redux for the containers to connect to the store. Then you can use mapStateToProps to get the data from the store to pass into the components as props. Check https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options for example.
How should I access the properties of an element without using the 'this' keyword in React Native? I have a function with which the parent class itself is bound as 'this' but I want to access the properties of the element that is being clicked. Here's the code-
import {Circle} from 'react-native-svg';
export default App extends Component {
constructor(props) {
super(props);
this.state = {activeX: null}
}
handleTouch(event) {
const x = event.target.cx; //How to access "cx" property here?
this.setState({ activeX: x });
}
render() {
return (
<Circle cx='10' cy='10' r='5' onPress={this.handleTouch.bind(this)}/>
<Circle cx='20' cy='20' r='5' onPress={this.handleTouch.bind(this)}/>
);
}
}
Try this
import {Circle} from 'react-native-svg';
export default App extends Component {
constructor(props) {
super(props);
this.state = {
activeX: null,
cx: 10
}
}
handleTouch = () => {
const x = this.state.cx
this.setState({ activeX: x });
}
render() {
return (
<Circle cx={this.state.cx} cy='10' r='5' onPress={this.handleTouch}/>
);
}
}
import ReactNativeComponentTree from'react-native/Libraries/Renderer/src/renderers/native/ReactNativeComponentTree';
And access the properties as-
const x = ReactNativeComponentTree.getInstanceFromNode(event.currentTarget)._currentElement.props.cx;
Sorry for leaving an answer but I cannot leave a comment since <50 rep.
You should edit the improve part of your answer, with the following bit:
import ReactNativeComponentTree from 'react-native';
instead of what you have right now,
import ReactNativeComponentTree from'react-native/Libraries/Renderer/src/renderers/native/ReactNativeComponentTree';
since is throwing an error (trying to import unknown module).
A better way of accessing the component properties in an event is actually by creating a component and passing it the needed data:
import { Circle } from 'react-native-svg';
class TouchableCircle extends React.PureComponent {
constructor(props) {
super(props);
this.circlePressed = this.circlePressed.bind(this);
}
circlePressed(){
this.props.onPress(this.props.cx);
}
render() {
return (
<Circle cx={this.props.cx} cy={this.props.cy} r={this.props.r} onPress={this.circlePressed}/>
);
}
}
export default App extends Component {
constructor(props) {
super(props);
this.state = {activeX: null}
this.handleTouch = this.handleTouch.bind(this);
}
handleTouch(cx) {
this.setState({ activeX: cx });
}
render() {
return (
<TouchableCircle cx='10' cy='10' r='5' onPress={this.handleTouch}/>
<TouchableCircle cx='20' cy='20' r='5' onPress={this.handleTouch}/>
);
}
}
NB: Performance tip from Facebook for event handlers:
We generally recommend binding in the constructor or using the property initializer syntax, to avoid this sort of performance problem. (i.e. to avoid the creation of the callback everytime a component renders)
ref: React Handling Events
(credits to https://stackoverflow.com/a/42125039/1152843)
You can change your event handler to a curried function like so:
import {Circle} from 'react-native-svg';
export default App extends Component {
constructor(props) {
super(props);
this.state = {activeX: null}
}
//Use ES6 arrow and avoid this.bind
//Curried function handleTouch accepts cx, cy as extra parameters
handleTouch = (cx, cy) => event => {
console.log(cx, cy) // This is how you access props passed to Circle here
console.log(event)
this.setState({ activeX: cx });
}
render() {
//You are actually invoking the handleTouch function here, whose return value is
//a function, which is set as the onPress event handler for the <Circle> component
return (
<Circle cx='10' cy='10' r='5' onPress={this.handleTouch(10, 10)}/>
<Circle cx='20' cy='20' r='5' onPress={this.handleTouch.(20, 20)}/>
);
}
}
Checkout the working snack below:
https://snack.expo.io/#prashand/accessing-props-from-react-native-touch-event