I'm calling a thunk from a component render function. It works fine if at initial app load the component that calls the thunk loads. however, if I load the app at a different route and then transition to the route which renders the component that calls the thunk , I get the following error:
Warning: setState(...): Cannot update during an existing state
transition (such as within render or another component's
constructor). Render methods should be a pure function of props and
state; constructor side-effects are an anti-pattern, but can be moved
to componentWillMount.
The thunk changes redux store state which is not used by any component in the app and is just used within the thunk via getState() to do some conditional logic. If I remove the dispatch actionCreator code from the thunk the error goes away.
What am i missing?
You just need to keep in mind the basic rule, you should never change your state in the render function of your component. The same rule applies to your component state, as well as to the redux store state. The warning you see on your console is due to the action you are dispatching in your render.
Refactor your code so that all dispatches and state changes take place in other lifecycle methods.
Related
I'm working with redux saga and redux toolkit. In the EachUser component, I don't understand why the component is mounting over and over again if I don't use the useEffect hook. Could someone help me understand why it is.
I'm not changing any props or state so I don't think infinite loop should happen but it is happening.
Here is the link to my code sandbox: Redux Saga With Redux toolkit
Happens following:
When you are trying to dispatch your FETCH_SINGLE_USER action on the top level of your functional component it will be executed on each render cycle (your function is re-rendered(executed) each time when props or state changed, also it will be re-rendered when the parent component is re-rendered (if you don't use React.memo).
So when you are dispatching your action on the top level of your functional component it will
fetch user from the server
->
update your store
->
updated store will cause re-render of the component as you are selecting updated state with useSelector
->
fetch user from the server action dispatched again (we are inside of the infinite loop)
So why we need useEffect - it is the hook that helps us to make some actions on special conditions. In the second parameter, you should put an array of dependencies, once dependency changed it will cause hook rerun. If the array is empty - hook will be executed only once when your functional component mounted. Also you can return cleanup function that will be executed, once your component unmounted. More documentation on useEffect hook here
try to remove dispatch from the array of dependencies
useEffect(() => {
dispatch({ type: sagaActions.FETCH_SINGLE_USER, userId });
}, [userId]);
calling a function inside useEffect and specifying it in an array of dependencies can cause an infinite rerender
Suppose I have a React class based component named as "ComponentA". Now I have called the action creator (getCategories) inside componentDidMount hook of this component and get its response inside componentWillReceiveProps through mapStateToProps setting up and carrying state inside redux. Now if I switch to "componentB" and trying to get this already setted up state inside componentWillReceiveProps through mapStateToProps of "ComponentB", the componentWillReceiveProps never invoked unless there is an API call which forcing this to invoke. I want to invoke this method of "ComponentB" everytime I switch to this component without API call. Please let me know the correct solution of this problem. Thanks
As per you description, It is hard to resolve your issue, but this is my try.
As you are switching the component, assuming you click some link, you will never get data in componentWillReceiveProps because whenever you are switching the component, that component only go through below process as a newly mounted component.
componentWillMount() -> Render -> componentDidMount().
This is the process for newly mounted component.
The data you want in componentWillReceiveProps will only come when you pass data from parent to child and not when you switch the component.
As you are using redux, and changing some state in one component (ComponentA), you can access the changed state the another component's (ComponentB) ComponentDidMount().
I am new to React and want to understand the difference from classic MVC.
I want to create a simple components that loads some data initially and renders let say a grid.
On some state or prop change it will reload the data and re-render.
What is the best approach in react from below two options?
using the lifecycle events to load the data, update some state and render while in another event will show some loading opacity.
Work with redux and react-redux? but in all example I cant see API calls.
Is this the role of a middleware (Thunk?)?
Will appropriate an explanation.
Both the approaches are correct. It depends on your use case. If you can avoid using redux in your app, use the lifecycle methods to make API calls (also called subscriptions in react documentation). If you think your app has many components and different components needs to share a state, then use redux.
You should also look at React hooks https://reactjs.org/docs/hooks-reference.html
You can use Effect Hook https://reactjs.org/docs/hooks-effect.html to make API calls and update your component's state.
Update:
Both Thunk and Sage are used to manage side effects in your application (making API calls from here). I've used saga, I don't know much about thunk.
How you would use redux-saga:
Say if you want to get some data for display on a button click, this is how it works:
On button click you dispatch an action, say GET_DATA
Your redux reducer will change some state on this particular action, say isLoading=true
You can use isLoading in your component to show a spinner/overlay
At the same time saga will listen to GET_DATA action and make the API call
If success, from Saga you'll dispatch an action, say GET_DATA_SUCCESS with the data from API call
Reducer will change isLoading=false and set the data in state, say apiData = { ... }
If failure, from Saga you'll dispatch an action, say GET_DATA_FAILED with the error code/message
Reducer will change isLoading=false and set the error in state, say apiError = { ... }
You can now use isLoading=false in you component to remove spinner and display the data (apiData) or error (apiError) in you component.
You can go through this tutorial to learn more https://redux-saga.js.org/docs/introduction/BeginnerTutorial.html
I have a React/Redux application with two components. I need to clear a portion of redux state when the first component unmounts, because the second component will error with the state in that form. I've tried to dispatch an action clearing the chunk of state when the first component unmounts, but the second component begins mounting before the first components componentWillUnmount method is called. When I view dispatched actions in redux-logger, I see the second component dispatching actions from componentWillMount and then componentWillUnmount actions from the previous component called.
This is not the expected behavior is it? I am also using react-router v4. Thanks!
Since React v16, the componentWillUnmount hook can fire asynchronously.
This means that you can't make any assumptions about the order (or timings) of the invocations of these hooks cross-component.
I understand that mapstatetoprops is mapping our Redux application state to our React component props, but i don't quite understand what's happening behind the scenes when a reducer returns a new state - how does that trigger a re-rendering of components that have props mapped to the application level state?
In pure React, setState triggers a re-render correct? Is something similar (or the same thing) happening via Redux?
Both Redux and React-Redux employ shallow equality checking.
In particular:
Redux's combineReducers utility shallowly checks for reference changes caused by the reducers that it calls.
React-Redux's connect method generates components that shallowly check reference changes to the root state, and the return values from the mapStateToProps function to see if the wrapped components actually need to re-render. Such shallow checking requires immutability to function correctly.
Well the whole point when you create a component using the redux "connect" function, is that behind the scenes you get connected to the redux state, and have a listener for the state changes.
So you create a simple component that gets his values from props, but those props are got from the state using the connect with "mapStateToProps".
Never dived in to the redux-react connect function, but if you want you can surely go ahead and see what it does exactly.
But the main point is what I explained above.