React Router 4 - componentWillReceiveProps() doesn't fire - reactjs

I'm using React Router 4.
When I render component with render parameter componentWillReceiveProps() it doesn't fire the fist time, so I need to click twice to sent props to the component.
I render like this:
const CartRoute = (props) => (<Cart itemsInCart = {this.state.itemsInCart} deleteItemFromCart = {this.deleteItemFromCart} {...props} />);
.....
<Switch>
.....
<Route path="/cart" render={CartRoute} />
</Switch>
Without Router (when all components are on the same page) it works ok.
Here is detailed description:
React router - Need to click LINK twice to pass props to Component

I think Reason is simple one, As per DOC:
React doesn't call componentWillReceiveProps with initial props during
mounting. It only calls this method if some of component's props may
update. componentWillReceiveProps() is invoked before a mounted component receives new props.
componentWillReceiveProps will not get called when first time component get rendered, at that time componentDidMount get called, when you do any changes in props values then only componentWillReceiveProps will get triggered. So first time if you want to do some calculation do that in componentDidMount method, like this:
componentDidMount(){
console.log('props values', this.props); //it will print the props values
}
componentWillReceiveProps is a Updating lifecycle method not Mounting method.
Mounting Methods:
These methods are called when an instance of a component is being
created and inserted into the DOM.
Updating Methods:
An update can be caused by changes to props or state. These methods
are called when a component is being re-rendered.
Check the difference between Mounting and Updating lifecycle method.

Related

Measuring how many times your components are rendering in React Native functional components

An easy way to see how many times components render in class components is the following:
render() {
console.log('component')
return <Component />
}
Is the equivalent in functional components useEffect?
useEffect(() => {
console.log('component');
});
When I call this I notice that 'component' is being printed over and over again. Does this mean that my component is being re-rendered over and over again unnecessarily?
Passing no 2nd argument causes the useEffect to run every render. Then, when it runs, it fetches the data and updates the state. Then, once the state is updated, the component re-renders, which triggers the useEffect again.
If you want to render once like componentDidMount pass '[]' as an argument or your state on which change you wanted to render.

How to update child component after props are changed in parent component

I have component TopicsView where I have property called choosenTopicId which I change on button click. Inside this component I have child component
<TopicViewOnSide TopicId={this.state.choosenTopicId} />
Inside TopicViewOnSide I use TopicId in componentDidMount() when I'm sending request from axios (HTTP GET) to get topic data from the server and then component TopicViewOnSide renders. My problem is when I change choosenTopicId by clicking button in TopicView, props are changed and it's good. But the child component doesn't rerender when the props are changed and I have old topic data because the child component didn't call componentDidMount() and there was no request to server. Can I somehow call the method componentDidMount() when the props are changed so the request from axios will be send and my data will be updated ?
You're looking for componentDidUpdate() which gets triggered after every state or prop change. The componentDidMount() method only runs a single-time.
You can do something like:
componentDidUpdate(prevProps){
if(this.props.blaw !== prevProps.blaw){
...execute your logic
}
}
That creates a check to do something only when props change.

`componentWillReceiveProps` explanation

I recently wanted to upgrade my knowledge of React, so I started from the component lifecycle methods. The first thing that got me curious, is this componentWillReceiveProps. So, the docs are saying that it's fired when component is receiving new (not necessarily updated) props. Inside that method we can compare them and save into the state if needed.
My question is: Why do we need that method, if changes in props of that component (inside parent render) will trigger the re-render of this child component?
One common use case are state (this.state) updates that may be necessary in response to the updated props.
Since you should not try to update the component's state via this.setState() in the render function, this needs to happen in componentWillReceiveProps.
Additionally, if some prop is used as a parameter to some fetch function you should watch this prop in componentWillReceiveProps to re-fetch data using the new parameter.
Usually componentDidMount is used as a place where you trigger a method to fetch some data. But if your container, for example, UserData is not unmounted and you change userId prop, the container needs to fetch data of a user for corresponding userId.
class UserData extends Component {
componentDidMount() {
this.props.getUser(this.props.userId);
}
componentWillReceiveProps(nextProps) {
if (this.props.userId !== nextProps.userid) {
this.props.getUser(nextProps.userId);
}
}
render() {
if (this.props.loading) {
return <div>Loading...</div>
}
return <div>{this.user.firstName}</div>
}
}
It is not a full working example. Let's imagine that getUser dispatch Redux action and Redux assign to the component user, loading and getUser props.
It 'serves' as an opportunity to react to the incoming props to set the state of your application before render. If your call setState after render you will re-render infinitely and that's why you're not allowed to do that, so you can use componentWillReceiveProps instead.
But... you are beyond CORRECT in your confusion, so correct in fact that they are deprecating it and other Will-lifecycle hooks Discussion Deprecation.
There are other ways to accomplish what you want to do without most of those Will-lifecycle methods, one way being don't call setState after render, just use the new incoming props directly in render (or wherever) to create the stateful value you need and then just use the new value directly, you can then later set state to keep a reference for the next iteration ex: this.state.someState = someValue, this will accomplish everything and not re-render the component in an infinite loop.
Use this as an opportunity to react to a prop transition before render() is called by updating the state using this.setState(). The old props can be accessed via this.props. Calling this.setState() within this function will not trigger an additional render.
Look at this article
the componentWillReceiveProps will always receive as param "NxtProps", componentWillReceiveProps is called after render().
some people use this method use this to compare nxtProps and this.props to check, if something should happen before the component call render, and to some validations.
check the react's documentation to know more about react lifecycle!
hope this could help you!
changes in props of that component (inside parent render) will trigger the re-render of this child component
You are absolutely right. You only need to use this method if you need to react to those changes. For instance, you might have a piece of state in a child component that is calculated using multiple props.
Small Example:
class Test extends Component {
state = {
modified: "blank"
};
componentDidMount(){
this.setState({
modified: `${this.props.myProp} isModified`
});
}
componentWillReceiveProps(nextProps) {
this.setState({
modified: `${nextProps.myProp} isModified`
});
}
render() {
return <div className="displayed">{this.state.modified}</div>
}
}
In this example, componentDidMount sets the state using this.props. When this component receives new props, without componentWillReceiveProps, this.state.modified would never be updated again.
Of course, you could just do {this.props.myProp + "IsModified"} in the render method, but componentWillReceiveProps is useful when you need to update this.state on prop changes.

How do I force a child component to rerender when given new props values?

I have tried this pattern.
ParentComponent
...
render(
return <ChildComponent newProps="newPropsValue />)
ChildComponent
...
ComponentWillReceiveProps{
this.setState({"propsKey": "newPropsValue"})
}
As far as I understand the initial component rendering is triggered by the props change, and as setState is asynchronous (for some reason), the rendering with the new state update is not done on the first pass.
However what I don't understand is why when it finally decides to update the state, it doesn't rerender the component. I thought state changes that are caused by setState always trigger a rerender.
So in the end I have a component that uselessly rerenders before the state is actually changed, and then does nothing when/if(?) the state is updated. I don't understand this behaviour at all.
setState will trigger componentUdpate -> componentWillUpdate -> render. props change will trigger componentWillReceiveProps before this chain. You can have a look here at this image about React lifecycle. You can see the different how React behave on props and state.
So:
However what I don't understand is why when it finally decides to update the state, it doesn't re-render the component.
Updating state by setState will trigger the render function (re-render). And props also trigger render as well.
Following your code:
componentWillReceiveProps:
this.props.newProps="newPropsValue"
this.state.propsKey="newPropsValue"
render: as above, nothing change.
If any event of childComponent setting propsKey by setState (onClick, onChange ...). Assuming setState({propsKey: "anotherValue"}). Then render will be triggered again with this.state.propsKey="anotherValue and this.props.newProps="newPropsValue"
Now let's update your childComponent's props within parentComponent, assuming newProps="latestPropsValue":
Before componentWillReceiveProps:
this.props.newProps="latestPropsValue"
this.state.propsKey="anotherValue"
After componentWillReceiveProps:
this.props.newProps="latestPropsValue"
this.state.propsKey="latestPropsValue"
How do I force a child component to rerender when given new props values?
If your render is using state then setState inside render. And if you are using props inside render, it also being updated accordingly
I have found a nice solution using key attribute. If we changed key property of a child component or some portion of React Component, it will re-render entirely. It will use when you need to re-render some portion of React Component or re-render a child component depending on props or state. Here is a example. I will re-render the full component.
import React, { useState, useEffect } from "react";
import { PrEditInput } from "./shared";
const BucketInput = ({ bucketPrice = [], handleBucketsUpdate, mood }) => {
const data = Array.isArray(bucketPrice) ? bucketPrice : [];
const [state, setState] = useState(Date.now());
useEffect(() => {
setState(Date.now());
}, [mood, bucketPrice]);
return (
<span key={state}>
{data.map((item) => (
<PrEditInput
key={item.id}
label={item?.bucket?.name}
name={item.bucketId}
defaultValue={item.price}
onChange={handleBucketsUpdate}
mood={mood}
/>
))}
</span>
);
};
export default BucketInput;

Will setState inside componentWillReceiveProps run before render?

The react docs mention that calls to setState are enqueued, and do not happen immediately. Does react make any guarantees that setState enqueued inside componentWillReceiveProps will execute before the next component render? Are either of these scenarios more likely than the other?
props change > componentWillReceiveProps called > setState enqueued > setState runs > render (which includes new state)
props change > componentWillReceiveProps called > setState enqueued > render > setState runs > re-rendered
Or, are both of these scenarios equally likely? Meaning does React not make any guarantees when setState will run relative to component lifecycle methods?
Here is a ES2015 code excerpt of my example:
import React from 'react';
class Widget extends React.Component {
componentWillReceiveProps() {
this.setState({foo: 'bar'});
}
render() {
return <div>
<a onClick={(e) => {
e.preventDefault();
this.props.triggerExternalPropsChange();
}}>
Click me to trigger new props
</a>
</div>;
}
}
Where triggerExternalPropsChange passes new props to the Widget component.
The only reason componentWillReceiveProps exists is to give the component an opportunity to setState. So yes, any state you set synchronously in it will be processed together with the new props. There won’t be two renders in this case, just one.
It's 1.
Calling setState() in componentWillReceiveProps() is an exception in the sense of executing state update before the component renders, so you will get both props changes and state changes applied in the same render.
Yep, both are likely. React will try to render anytime it gets new props or state and because it does dom diffing, it tries to render as often as possible. You have options to control it though, using shouldComponentUpdate you can check and wait until both props and state have been updated before rendering.

Resources