I have observed that the getDerivedStateFromProps of the React Component is called in at least 2 cases:
when the props are changed, e.g. the component imports Redux store data via component's props when the Redux store have received new data from the external API (either as a result from the request initiated by the component or as a push from external event)
when the component's setState is called, e.g. user can update data in some element of the component and this update is handled by the procedure that calls setState.
it is also called during the navigation, when props.match.params.... are changed.
So - I would like determine the cause (1. or 2.) of the getDerivedStateFromProps and make distinct actions in each case. How it is possible to make such distinction. Maybe this is not possible to do. Or maybe my architecture is flawed if I wish to do this?
The main problem for me is - how to pass business object from the redux store (to which the props of component points to) into this.state of some component for further local manipulation?
My previous attempt is documented in the question ReactJS setState conflicts with getDerivedStateFromProps in which the more concrete code examples are available.
Related
I know using "key" prop on any React component will re-mounts if there is a change in key value.
Using "ComponentShouldUpdate" lifecycle method will just update the component instead of re-render.
In what cases we should use "key" vs "ComponentShouldUpdate"? Does using one provides advantage over other ?
I think you should revisit the documentation because what you know is not correct.
a component gets updated when props or state change no matter if you have keys or not in the component
shouldComponentUpdate gets executed every time before render and tells if the component should be re-rendered or not. for regular components the method just returns true. you can overwrite it. pure components do a shallow check.
keys only help react know what changed during a render/re-render. they don't stop/prohibit a re-render.
You should use shouldComponentUpdate as a optimization.
key and componentDidUpdate are used for entirely difference purposes.
From the docs,
React implements a heuristic O(n) algorithm based on two assumptions:
Two elements of different types will produce different trees.
The developer can hint at which child elements may be stable across
different renders with a key prop.
What this means is that if a key passed to a react component changes, react will tear down the old tree represented by the component at DOM and create a new tree(unmount and then remount the component even if nothing has changed except the key).
On the other hand, componentDidUpdate will run after a component has been updated i.e a prop or state for the specific component has changed. Update will not result in the teardown of the tree from the state.
You should not be using key in usual cases and let props/state changes trigger componendDidUpdate and handle your logic there. Key is used on some occassions where you have a large amount of state logic and you want to reset your state logic to initial state i.e remount your component from scratch. Essentially, you should avoid using key to unmount and remount your component as this operation affects performance.
This question is about internals for partial re-renderings with React-Redux.
To explain what I mean, I will first introduce a very crude technique for managing state without any state management libary.
The technique uses a a huge "AppState"-object that is owned by the top-level App-component.
Suppose that this AppState holds not only state-properties, but also several callbacks that mutate those state-properties.
Furthermore, suppose that we use props to pass down this AppState throughout the entire component hierarchy.
Thanks to the ES6-spread syntax, passing a huge number of props can be done without a lot of boilerplate code.
In the top-level App-component, it will look like this:
<ChildComponent {...this.state} />
In all other components, it will look like this:
<GrandChildComponent {...this.props} />
It is important to note that the ES6-spread syntax does not actually pass the AppState-object. Instead, it extracts all the AppState-properties and passes them as separate props.
Now we should distinguish between top-level properties and nested child-properties of the AppState:
If I mutate a top-level property of this AppState by calling setState, then the entire app will re-render (unless I use things like pure components).
However, if I change a nested child-property of this AppState, then nothing will happen because React does not notice the property change.
This leads to my final questions:
What is the render-performance of this crude approach in comparison to Redux?
How exactly does Redux handle "partial renderings", such that only some of the Components re-render after a state mutation?
If I mutate a top-level property of this AppState by calling setState, then the entire app will re-render (because everything depends on the AppState).
If you mutate and use pure components then nothing will render, you change state by creating a new state object.
However, if I mutate a nested child-property of this AppState, then nothing will happen because React does not notice the property change.
This is only true if you mutate and components are pure.
What is the render-performance of this crude approach in comparison to Redux?
Prop drilling will re render the entire tree but branches that use state that didn't change won't re render if they are pure. Prop drilling is bad for maintenance because if you need to refactor grand child state logic you may need to refactor the whole tree or branch. But from a performance point it would not take a big hit provided that you use pure components and are careful when passing callbacks and not re creating them on every render (see useCallback).
How exactly does Redux handle "partial renderings", such that only some of the Components re-render after a state mutation?
React-redux useSelector or connect mapStateToProps are always called every time dispatch changed state and before rendering.
If the result is different than last result then react-redux will trigger render of the component. If the component gets props then a render could also be triggered because props change and mapstate/selector will be executed.
A connected component will observe state and render when the result of mapState or selector has changed. An example app with logs showing what react-redux will execute can be found here
For state management, you don't necessarily have to use Redux, if your use cases are small, maybe React Hook would be perfect for you.
For React rerendering matter, what I know is there are several strategies (useMemo, PureComponents) provided by React for managing and improve the performance. It really depends on how you manage your components.
One example is using PureComponent, even if you have a large state in your top-level app.js, if you manage the child components properly, they will not re-render if their receiving props haven't changed.
For my application, I want to create a component who's sole purpose is to update when there is a change to the Redux store.
I have achieved this with a componentDidMount() that checks if the component's state matches the store and sets the state if not.
My solution works, and is suitable enough for the situation, but it seems like a lot of code for a simple function.
How can one achieve the same outcome, a component that updates on Redux store change, using a functional component or a more simple stateful component?
Update: Thanks to the comments below, I have a new working the passes state information as props.
React components renders due to changes in props and state, therefore when you connect your component to Redux store
and supply mapStateToProps, when redux store update the mentioned props that you will return from that function, your component will re-render. You can detect changes via componentWillReciveProps life cycle method.
I am using redux, react, react-router and reselect. There is a screen that contains two components, the Header and the Body. There is a component in the Header to select an ID. When a new ID is selected a new action is dispatched to update the ID in the state in redux.
Based on that ID there should be an asynchronous API call to load the element from the server and store it in the state, which should then trigger a render of the screen and display the element in the Body. The loaded element would then be extracted from the state with reselect.
The real-life scenario is a bit more complex than that, because there are many different Body components with different API calls and only one Header component. But they can be treated as different screens. So, for example:
Screen 1:
components: Header, BodyTypeA; API to call: apiA
Screen 2:
components: Header, BodyTypeB; API to call: apiB
My understanding is that the API call should be done in the reducer when it stores the new ID in the state. But how to determine which screen is being shown and which API to call if the action is dispatched by a component shared across screens? Can I somehow subscribe in the Body to changes to the ID and trigger the API call from within the screen? The screen type is determined by the react-router. Would the reducer have any access to the router to determine which screen is being shown? Are there any best practices for handling such a scenario?
Seems like you may be overthinking this. So, one thing at a time:
My understanding is that the API call should be done in the reducer when it stores the new ID in the state.
Unless you'll be using redux-loop that allows returning an action from a reducer you're wrong. In principal reducers CAN NOT dispatch any actions, they only consume them. It's the middleware layer (or action creator) where you dispatch your actions and may call your APIs.
But how to determine which screen is being shown and which API to call if the action is dispatched by a component shared across screens?
To determine "where you are" it's best to keep routing information in your state tree. Since you're using react router anyway consider using https://github.com/reactjs/react-router-redux to expose route information in your state tree and then access it from your middleware / action creators / selectors.
Can I somehow subscribe in the Body to changes to the ID and trigger the API call from within the screen?
Yes, technically you can subscribe to store changes, but normally you wouldn't have too - see my other points and hopefully it's clear enough.
The screen type is determined by the react-router. Would the reducer have any access to the router to determine which screen is being shown?
No (in general) reducers only have access to their slice of state, so while your reducer may react to react router actions (if you'll use react-router-redux - see above) to store route details you require, but in principle it should be up to your selectors and/or connected components to construct / pull data required for given component from the state tree.
Are there any best practices for handling such a scenario?
I guess use react-router-redux, introduce a middleware that will trigger an API call in response to your action and will dispatch consecutive action containing data returned from the API. That action you'll handle in your reducer, storing data in the tree.
And a random tip, if you have components like bodyTypeA, bodyTypeB then those components can (should even) keep information if they're A or B and propagate that to the action creator. E.g. if you have an action creator called requestForId(ID) you'd modify signature to be requestForId(ID, type) and in your component / callback (whenever you're invoking that action creator) you'd be passing not only the ID but also the type, i.e. bodyTypeA would call it with requestForId(ID, 'A').
I have a ReactJS component that I'm developing which needs to get some information from the URL. To do this I've been utilizing the componentWillReceiveProps lifecycle method to look at props.location.query and dispatches actions to a Redux store in order to update the known state. The problem that I'm running into is that it doesn't appear that componentWillReceiveProps is being called for my component until that component has focus. I can reload the page which hosts this component and the render is called but componentWillReceiveProps is never called first.
Clearly I'm either understanding the lifecycle incorrectly with respect to componentWillReceiveProps or there is something else either wrong in my component or application which is make it behave differently than it is intended. Please set me straight either way.
componentWillReceiveProps isn't called on the first render.
From the React Docs:
"Invoked when a component is receiving new props. This method is not called for the initial render."