Comments (18)
@jeff-lau a new set of props coming in for a component will always cause it to try to re-render (I say try because you can stop rendering with shouldComponentUpdate
). Think of components as functions and of props as the arguments to the functions. Receiving props is like calling the function. If you call add(1, 2)
you expect 3
. If you call it again with add(3, 3)
you expect 6
.
componentWillReceiveProps
can be used to react to incoming new props and possibly trigger state changes, but a component will always try to re-render regardless if you call setState
or not in that life cycle method.
from react-guide.
In your example you're mutating the this.props
object which is not allowed because React won't notice the change. The props do indeed change but the component is unaware of this. That's why you need to forcefully trigger an update, either by calling setState
or forceUpdate
. Then, React will see the new value for this.props
and use it.
You should never manually update this.props
. If you want a component to send new props to a child component then those new props should be computed at render time e.g. as a derivation of the parent's state.
Container {
state= { foo: 123 }
handleEvent() {
this.setState({ foo: 456 })
},
render() {
return <Child foo={this.state.foo} />
}
Child {
render() {
return <div>{this.props.foo}</div>
}
}
from react-guide.
@NiGhTTraX thank you for replying!
I find that, if a parent container changes the props passed in to a child component. The child component does not re-render automatically. The way I can get it to re-render is to update the state of the child component with the new props in the componentWillReceiveProps method.
That seems to be the way how react behaves?
thanks,
from react-guide.
Guys, I am having a problem with re-rendering of a component (and came here Googling) on its props change:
Component rendered in parent:
<JobList project={this.state.element} jobs={this.state.activeJobs} user={this.props.user} onChange={handleChange} title="Active Jobs"/>
Change state in parent:
const handleChange = (...) => {
...
this.setState({
exclusionList: exclusionList,
activeJobs: activeJobs,
completedJobs: completedJobs,
});
...
}
onClick method in child:
const handleClick = (job, action) => {
this.props.onChange(job, action);
}
<button className="btn btn-icon btn-danger btn-simple btn-round btn-sm" onClick={() => handleClick({value:element.id, title: element.title, complete: element.complete}, 'removeJob')}><i className="fal fa-times"></i></button>
Set state fires for sure, as another component, that takes its props from state re-renders immediately:
<Progress value={(this.state.completedJobs.length/(this.state.activeJobs.length + this.state.completedJobs.length))*100} />
I hope I am not hijacking the thread.
EDIT: RESOLVED!
I found my (probably newbie mistake). It was very simple: I was assuming that the constructor of the child would be called whenever props is changed and was copying props to state, then using state in the render functions. Apparently, constructor of child did not run when props were changed. Once I started using props instead of state in child function everything started working.
from react-guide.
I think should be use Vuex, put the model object for react with parent and children components. in vue template(ui), you can bind the object (from $store.state.object). when the object changed by this.$store.commit('updateObject', newObject); your children component will be render. The means: parent, children component, even sibling components share same model object with Vuex
from react-guide.
Hello. Above in thred we have a lot clarification about why props does not trigger re-render. But the React docs tells that they should do. Why?
An update can be caused by changes to props or state.
https://reactjs.org/docs/react-component.html#updating
from react-guide.
@jeff-lau a new set of props coming in for a component will always cause it to try to re-render (I say try because you can stop rendering with
shouldComponentUpdate
). Think of components as functions and of props as the arguments to the functions. Receiving props is like calling the function. If you calladd(1, 2)
you expect3
. If you call it again withadd(3, 3)
you expect6
.
I didn't test it with react class components
but whats has happened to me while using react functional components
and redux
changing props is this:
const addresses = props.addresses
const [currentAddress, setCurrentAddress] = useState(addresses && addresses[0])
I am using both the props and the state of addresses
. It seems like my props didn't apply to the currentAddress
when the render function is called but this could be a side effect of using useState as I had to manually change the state every time the address changes as the render function must have been called otherwise I won't be able to see my props getting changed:
useEffect(() => {
setCurrentAddress(addresses && addresses[0])
}, [addresses])
from react-guide.
@Guneetgstar The combination of useState
and useEffect
as you have done, is the right way to keep state and props in "Sync". The reason why a prop change wouldn't update your UI is
- When react first renders the component it (per your code) takes the
addresses
prop and creates a statecurrentAddress
. - When
addresses
is changed, then react of course re-renders your component. - BUT, the
useState(addresses && addresses[0])
does not take into account the value of the expressionaddresses && addresses[0]
. Because it already has a state value from previous render. - So your UI doesn't show the new value of the expression
addresses && addresses[0]
.
But here is the thing, in your example, you do not need to create a state at all. If what you want is the value of the expression addresses && addresses[0]
and show it somewhere in the UI, then why bother storing it in a state? State is supposed to be something that is local to the component, there is really no need to sync it with your props. Rather just derive what ever you want to show from the props and show it directly. Like
export function MyComponent(props) {
const { addresses } = props;
return (
<div>Address is {addresses ? addresses[0] : 'Unknown'}</div>
);
}
This is a very common mistake to think that we need to sync the state with the prop to show in the UI, I did similar mistakes earlier. I would really recommend you to read this article by @kentcdodds
https://kentcdodds.com/blog/dont-sync-state-derive-it
from react-guide.
@Guneetgstar I see. Your use case may vary, but it is also possible to do something like
const { addresses, dispatch } = props;
const currentAddress = addresses ? addresses[0] : '';
return (
<input type="text" value={currentAddress} onChange={e => {
const newAddresses = addresses ? [...addresses] : [];
newAddresses[0] = e.target.value;
// call redux dispatch to update address
dispatch({
type: 'UPDATE_ADDRESS',
payload: newAddresses,
});
}} />
);
But of course it would update your redux store on every keystroke. If you are mapping only needed props to your components, then it wouldn't matter much. Although if performance does become an issue then you can copy the prop to state, keep then in sync and then debounce any update to the local state through your redux dispatcher.
from react-guide.
Thanks @NiGhTTraX for the clarification. I am just starting with React and I wasn't sure that updating the props from outside will cause re-render (because this is what I need). I came across the stackoverflow example and I thought it is indeed not okay to change props inside a component. Your clarification clears things up.
Bottom line is I am passing props from parent to child without of course mutating them ever. So if the prop does change (from an even external component, like GrandParent) then react will re-render.
The only situation I have found to actually look for prop change is, if I am using one of the props to set an initial state. Then I would not set any state at constructor
. I would rather use getDerivedStateFromProps(nextProps, prevState)
and do it there. I may compare against prevState
to check if it is actually necessary for me to update.
Further down I may use shouldComponentUpdate
to fine tune it further.
So please correct me if my understanding is wrong. Thank you.
from react-guide.
@swashata your understanding is correct. I just want to clarify one small thing for future readers:
I would not set any state at constructor. I would rather use getDerivedStateFromProps(nextProps, prevState) and do it there
At least with the current API in 16.3.0, state needs to be defined in the constructor before calling getDerivedStateFromProps
. If you don't initialize it then you get the following warning:
Warning: Foo: Did not properly initialize state during construction.
Expected state to be an object, but it was undefined.
getDerivedStateFromProps
is meant to replace componentWillReceiveProps
so its main purpose will be to adjust existing state based on new incoming props, not to define the initial state.
from react-guide.
@NiGhTTraX Thanks for the pointer. I was already setting this.state = {...}
with some initial value. I did face the error when I didn't do it.
Bdw, could you please do a quick review of the codebase I am working on? I will be very glad 😅
from react-guide.
Great pointer about the forceUpdate when new props are passed to the component in some edge case scenarios. I may try the getDerviedStateFromProps in the future. I agree with your comment @swashata that "The only situation I have found to actually look for prop change is, if I am using one of the props to set an initial state", plus of course setting static items. I ran into a conundrum earlier today where I wanted to get the derived state from the initial props, so I did this https://stackoverflow.com/questions/50103629/passing-data-from-ajax-call-to-view-in-react-native. Seems to work for me, thought I'd pass the knowledge along. Thanks for clearing some things up for me @NiGhTTraX; reading this conversation helped validate my solution.
from react-guide.
@NiGhTTraX I have a small question:
I have shouldComponentUpdate()
in child component. For the first render, props seems to be passed, on the state change of the parent shouldComponentUpdate()
seems missing the props.
Is is somewhat expected?
from react-guide.
Hey @bologer, can you provide some example code?
from react-guide.
Thank you, @finkbg. I had made the exact same wrong assumption about the constructor()
function running each time the properties changed. Your post helped me understand the issue I was having, and how to fix.
from react-guide.
In your example you're mutating the
this.props
object which is not allowed because React won't notice the change. The props do indeed change but the component is unaware of this. That's why you need to forcefully trigger an update, either by callingsetState
orforceUpdate
. Then, React will see the new value forthis.props
and use it.You should never manually update
this.props
. If you want a component to send new props to a child component then those new props should be computed at render time e.g. as a derivation of the parent's state.Container { state= { foo: 123 } handleEvent() { this.setState({ foo: 456 }) }, render() { return <Child foo={this.state.foo} /> } Child { render() { return <div>{this.props.foo}</div> } }
Excellent! Child should not keep this as state if it is property replication. If it is transforming then event passing and transform again.
from react-guide.
@swashata I acknowledge your suggestion but there was a need to store currentAddress
in the local state as currentAddress
is something that is a candidate in my UI that might be saved in redux
and hence further propagated to the props
. But until the user don't save the currentAddress
it must be available in the UI only as user might edit it.
+1 for 3rd point.
from react-guide.
Related Issues (9)
- Question: does state have to be serializable? HOT 2
- State can get initial value from parent Component? HOT 2
- Table not rendering on GitHub HOT 2
- Are props geometrical properties of a component? HOT 2
- Broken link
- Licensing? HOT 1
- Document component > mixin > lib guidelines
- props cannot change inside Component? HOT 10
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react-guide.