App Component:
class App extends React.Component {
constructor() {
super();
this.state = {
user: 'Dan',
};
}
render() {
return (
<React.Fragment>
<label>
<b>Choose profile to view: </b>
<select
value={this.state.user}
onChange={e => this.setState({ user: e.target.value })}
>
<option value="Dan">Dan</option>
<option value="Sophie">Sophie</option>
<option value="Sunil">Sunil</option>
</select>
</label>
<h1>Welcome to {this.state.user}’s profile!</h1>
<p>
<ProfilePageClass user={this.state.user} />
<b> (class)</b>
</p>
</React.Fragment>
)
}
}
ProfilePageClass ( the problem is here ):
class ProfilePageClass extends React.Component {
showMessage = () => {
alert('Followed ' + this.props.user); // This get wrong value (new props)
};
handleClick = () => {
setTimeout(this.showMessage, 6000); // This get wrong value (new props)
};
render() {
return <button onClick={this.handleClick}>Follow</button>;
}
}
setTimeout does not display the message corresponding to the user that was originally followed
I think it's a problem with the props or this , but I'm not sure.
Can anyone tell me what is going on?
Nothing to do with the this
keyword. When the app state changes, your component instance receives new props
values, and the setTimeout
callback that runs after they have changed will access the new values. This is sometimes desirable, sometimes not.
This is one of the differences between function components and class
components . To get the user profile that was rendered when you clicked the button, you need to explicitly remember it when the button is clicked (or rendered):
class ProfilePageClass extends React.Component {
handleClick = () => {
const user = this.props.user;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
setTimeout(() => {
alert('Followed ' + this.props.user); // current value (wrong)
alert('Followed ' + user); // old value (expected)
}, 6000);
};
render() {
return <button onClick={this.handleClick}>Follow</button>;
}
}
With a function component, you can't get it wrong (but accessing the current value is next to impossible without useRef
):
function ProfilePageClass({user}) {
const handleClick = () => {
setTimeout(() => {
alert('Followed ' + user); // old value (expected)
}, 6000);
};
return <button onClick={this.handleClick}>Follow</button>;
}
It's likely there's a problem regarding the setTimeout
your using, in which you're losing reference to the actual prop you wish to display. You can add something like this to your parent component:
this.myRef = React.createRef();
This will generate a ref that you can later pass in to the child component. You can set the refs current item in this fashion:
this.myRef.current = this.state.user
in order to populate the ref.
Try this modification, as there might be handleClick
is not auto bound.
import React from "react";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
user: 'Dan',
};
}
render() {
return (
<React.Fragment>
<label>
<b>Choose profile to view: </b>
<select
value={this.state.user}
onChange={e => this.setState({ user: e.target.value })}
>
<option value="Dan">Dan</option>
<option value="Sophie">Sophie</option>
<option value="Sunil">Sunil</option>
</select>
</label>
<h1>Welcome to {this.state.user}’s profile!</h1>
<p>
<ProfilePageClass user={this.state.user} />
<b> (class)</b>
</p>
</React.Fragment>
)
}
}
Profile alert
class ProfilePageClass extends React.Component {
//Define a constructor here
constructor(props){
super(props)
// Bind handleClick , so that `this` will point to parent component when you pass to child
this.handleClick= this.handleClick.bind();
}
showMessage = () => {
alert('Followed ' + this.props.user); // This get value (new props)
};
handleClick = () => {
setTimeout(this.showMessage, 100); // This get value (new props)
};
render() {
return <button onClick={this.handleClick}>Follow</button>;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.