I'm trying to re-render some values in my react-native app.
I have used componentWillRecieveProps() for that.
But, componentWillRecieveProps() is executed before re-render,setting wrong values in state.
componentWillReceiveProps(nextProps) {
const {
navigation
} = nextProps;
const flatListData = navigation.getParam("flatListData", "NO-DATA")
console.log(flatListData)
this.setState({
dataSource: flatListData
})
}
componentWillRecieveProps will always executes before re-render, it's default behavior.
You probably need componentDidUpdate which will execute after re-render.
Note: componentWillRecieveProps is replaced by getDerivedStateFromProps
Reference to this information.
The component method componentWillReceiveProps() is deprecated in later react versions.
You probably need componentDidUpdate.
Another problem I can see in the code is setting of state from props this is a common anti pattern and should be avoided. You can read more about better alternatives here
It's not clear why you're requesting navigation.getParam in componentWillReceiveProps. They're two very different things. If this component is a react navigation route, then parameters will be set. If this component is a child of another component then componentWillReceiveProps will be called with updated parameters when the parent component changes parameters.
Related
I have a few questions related to each other regarding React hooks: useState and useCallback.
When exactly is a functional update required?
1.1. If the setter function receives a function its argument will ALWAYS be the previous state?
If I want to update the parent state from the child component, how should I pass the setter to the child- wrap it in another function as a callback as explained here? just pass it directly as suggested here?
2.1. What are the reasons and advantages/disadvantages of each approach?
If I can just pass it directly and I am using memo, is useCallback required as explained here?
If I want to use the most recent state data when updating the parent state from the child, how should I do this?
4.1. Is passing a callback to the child useful in that case?
1. When exactly is a functional update required?
You may need to update any state on your component. For example, you are getting user from server via api and you need to store that user on your component. To do so, you need useState to store that user object. Here is the example:
const [user, setUser] = useState({}); // declaration
let newUser = u; // u is coming from api
setUser(newUser);
1.1. If the setter function receives a function its argument will ALWAYS be the previous state?
Yes. setter function like setState is used in class component. Here is the example of only update a state field:
this.setState({username: 'khabir'});
here you are updating state using previous state:
this.setState(prevState =>{
return{
counter : prevState.counter +1
}
})
2. If I want to update the parent state from the child component, how should I pass the setter to the child- wrap it in another function as a callback as explained here? just pass it directly as suggested here?
Both examples are same. you can use anyone.
3. If I can just pass it directly and I am using memo, is useCallback required as explained here?
If you pass any function reference to the child component from parent component, it is being created on every render of Parent and hence prevProps and props is not the same anymore even though they are.
To apply the memo, we need to make sure that function reference is not unnecessarily recreated on every render of Parent. That's why useCallback is used. Please read that article completely for better understanding.
4. If I want to use the most recent state data when updating the parent state from the child, how should I do this?
You can not update parent state directly from child component but you can send function reference to child component and call that function from child component that defined (the function) on parent component. In that function body (in parent), you can update your state of parent component.
4.1. Is passing a callback to the child useful in that case?
Yes as I said on the answer of question number 4.
right now im have tree component like this
<UserOrderApproval>
<Table>
<TableRow>
<ComponentList />
</ChildrenProps1>
</Parent>
</UserOrderApproval>
im take props from redux in UserOrderApproval component, and passing that props to every children component. The problem, when children component make some change in redux, the state from UserOrderApproval component will change & make all children component re render & make component life cycle run again. How to do prevent this?
How best practice to passing props from parent to nested children like this?
Many Thanks
As KuchBhi said, you'll need to use the shouldComponentUpdate lifecycle method.
shouldComponentUpdate is called any time when new props or state are passed to the component and by default returns true (might only return true for updated props, not 100% sure). The method accepts two parameters: nextProps and nextState. You can then compare these to this.props and this.state to decide whether you should update or not.
The default/typical implementation of this method is something along the lines of this (pseudo):
shouldComponentUpdate(nextProps, nextState) {
//Really it's a deeper equality check, not just the props/state object
return this.props !== nextProps || this.state !== nextState;
}
What you can do as an alternative is build this out a bit more with cases where false is returned. Here is an example from one of my projects where I only want to rerender when two specific props are different:
shouldComponentUpdate(nextProps) {
const minUpdated = this.props.min !== nextProps.min;
const maxUpdated = this.props.max !== nextProps.max;
return minUpdated || maxUpdated;
}
The component also has the props such as scale, align, width, etc. but I don't want to update when I receive those as new props so I don't check to see if they're not equal.
You could essentially just return false in this method and never update after the initial load, but I would avoid that as it defeats the purpose of react.
edit: As varoons said, this is likely a great scenario for you to use the new context API and I highly recommend looking into it, but it is useful to know about component lifecycle methods as well.
Use shouldComponentUpdate(), pure components, or connect redux to only the child components that need them.
https://reactjs.org/docs/react-component.html#shouldcomponentupdate
https://reactjs.org/docs/react-api.html#reactpurecomponent
This is a good scenario to use React's context api as this seems like a prop drilling case - You are passing data down to components that do not use it.
You could make UserOrderApproval(assuming it is the parent connected to the global state/redux) the context provider and ComponentList the consumer. This way only the components handling/using the data will re-render.
https://reactjs.org/docs/context.html
https://scotch.io/tutorials/get-to-know-reacts-new-context-api
I am deleting a record from db, for this I am calling an API. When I received an
API response of a successful deletion, I need to re-render all the component again like reload does. I tried it with this.forceUpdate and shouldComponentAgain but no luck.
I also tried with componentDidUpdate, it works but it is calling API infinite times. Below is my code how I used componentDidUpdate:
componentDidUpdate(){
let newThis = this;
getAccounts().then(function(response){
if(response.status===200){
newThis.setState({
Accounts:response.data
})
}
});
}
Please tell me the way to re-render like reload do, but without re-loading the whole page.
When using componentDidUpdate, you should always have a conditional setState which denotes that you need to perform something because the current state or current props is not equal to previous state or props.
componentDidUpdate always gets called whenever your component has updated. In your case what is happening is that you are calling setState without any condition which updates your component, and setState is called again causing an infinite loop in updating the component.
You should have something like this check here:
componentDidUpdate(prevProps, prevState){
let newThis = this;
if(newThis.props.{some-variable} !== prevProps.{some-variable}) {
getAccounts().then(function(response){
if(response.status===200){
newThis.setState({
Accounts:response.data
})
}
});
}
}
Adding conditional setState is very important here else you will end up in an infinite loop.
As per the official docs as well:
You may call setState() immediately in componentDidUpdate() but note
that it must be wrapped in a condition or you’ll cause an infinite
loop. It would also cause an extra re-rendering which, while not
visible to the user, can affect the component performance. If you’re
trying to “mirror” some state to a prop coming from above, consider
using the prop directly instead.
Hope it helps.
If you want to render the component again, then change the props from the parent. If props change then child component automatically going to render. And by this features, you can also render the selective component.
I'm confused about the new lifecycle of react 16, getDerivedStateFromProps use case. Take below code for example, getDerivedStateFromProps is not needed at all since I can achieve what I want with componentDidUpdate.
export class ComponentName extends Component {
//what is this for?
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.filtered !== prevState.filtered && nextProps.filtered === 'updated') {
return {
updated: true //set state updated to true, can't do anything more?
};
}
return null;
}
componentDidUpdate(prevProps, prevState) {
if(prevProps.filtered !== this.state.filtered && this.state.filtered === 'updated'){
console.log('do something like fetch api call, redirect, etc..')
}
}
render() {
return (
<div></div>
);
}
}
From this article:
As componentWillReceiveProps gets removed, we need some means of updating the state based on props change — the community decided to introduce a new — static — method to handle this.
What’s a static method? A static method is a method / function that exists on the class not its instance. The easiest difference to think about is that static method does not have access to this and has the keyword static in front of it.
Ok, but if the function has no access to this how are we to call this.setState? The answer is — we don’t. Instead the function should return the updated state data, or null if no update is needed
The returned value behaves similarly to current setState value — you only need to return the part of state that changes, all other values will be preserved.
You still need to declare the initial state of the component (either in constructor or as a class field).
getDerivedStateFromProps is called both on initial mounting and on re-rendering of the component, so you can use it instead of creating state based on props in constructor.
If you declare both getDerivedStateFromProps and componentWillReceiveProps only getDerivedStateFromProps will be called, and you will see a warning in the console.
Usually, you would use a callback to make sure some code is called when the state was actually updated — in this case, please use componentDidUpdate instead.
With componentDidUpdate you can execute callbacks and other code that depends on the state being updated.
getDerivedStateFromProps is a static function and so has no access to the this keyword. Also you wouldn't have any callbacks placed here as this is not an instance based lifecycle method. Additionally triggering state changes from here could cause loops(e.g. with redux calls).
They both serve different fundamental purposes. If it helps getDerivedStateFromProps is replacing componentWillReceiveProps.
getDerivedStateFromProps basically can save you one render cycle. Let's say due to some props change, you have to update some state and the UI responds with the new state. Without getDerivedStateFromProps, you have to wait until componentDidUpdate is invoked to make the prop comparison and call setState to update the UI. After that, componentDidUpdate is invoked again and you have to pay attention to avoiding endless rendering. With getDerivedStateFromProps, the UI update just happens earlier.
I am a newbee in react + flux. I'm bit confused about when and how does re-rendering happens when an event is emmitted by stores. In my app I am listening to a event in the function componentWillMount() which is called just before rendering happpens. It's working fine and my views are getting updated. I have just once concern that what causing my component to re-render.
Below is the codes.
function to update store
createTodo(text){
const id = Date.now();
this.todos.push({
id,
text,
complete:false
});
this.emit("change");
My component -- listener method.
componentWillMount(){
TodoStore.on("change", () => {
this.setState({
todos: TodoStore.getall()
})
})
}
Here what is causing my component to re-render? Can you please explain me in details.
Every time you call setState the component will re-render.
See: https://facebook.github.io/react/docs/component-api.html
setState() will always trigger a re-render unless conditional rendering logic is implemented in shouldComponentUpdate(). If mutable objects are being used and the logic cannot be implemented in shouldComponentUpdate(), calling setState() only when the new state differs from the previous state will avoid unnecessary re-renders.
Whenever you call setState() in a react app it causes the state to render.
Basically every time state changes your render function inside your react component will get executed and your UI will be reflected of the new changes