I have an application that creates a new record and redirect the history to the new record page using react-redux-router push. This redirection is made by a "smart component" inside another smart component.
The state of these components is stored on a redux store.
After redirection if I go back to the previous page it's state is dirty.
Is there a way to reset the state ? Or should I manually clean it up before the redirection.
Currently I'm listening on the reducer for LOCATION_CHANGE and resetting it but this seems manual and hacky.
Shouldn't the component unmount when it's route is not rendered anymore?
I'm unclear from your question - is the state that you're wanting to be reset stored within that component (setState) or within the Redux store?
If it's within that component, and the component is unmounted, then its state should be automatically reset.
If it's within the Redux store, then the whole point of the Redux store is that it exists persistently, outside of whatever components are mounted. One common way of resetting state in that case would be to dispatch a clear or reset action within the component's componentWillMount (i.e., the component ensures that it always starts with a good state).
Related
In my React app, I have a redux reducer which sends a List as props to my component.
I copy the prop to local state, and show as drop down. User changes the Dropdown so my local state changes.
On click of cancel , I am calling redux Toastr which triggers a method to reset my state with the original props.list. But for some reason the props.list also changed similar to my state change. With my knowledge i thought props passed to the componeent will not be changed until again i call action creator.
Anyone faced similar issue? or i am doing something wrong
Sorry for not posting the code, which I will prepare a demo if needed. Thanks!
What you are doing is an anti-pattern as you are breaking react's rule of single source of truth. You can't hold state internally in a component that is tied up with your redux state and expect it work smoothly. A similar issue of breaking the single source of truth arise when using solely React without Redux and when you try to pass props as state. In this case there is a new lifecycle hook static getDerivedStateFromProps but even this hook is advised to be used sparsely you can read about it here. So if your intent is to reset state back to it's original value, you can either:
Use static getDerivedStateFromProps (which is reserved mostly for UI)
Use a key prop which will reset you back to your initial state
Use a memoization helper such as memoize-one
Isn't that a very expensive affair?
For example, if I clicked a button that toggles something... Does React need to recreate the entire Virtual DOM just for that one action and diff it as well?
When you call React Redux's connect on components, you're wrapping them in a component called Connect. The component reads the store from the <Provider>'s context. When you dispatch an action, the Redux store gets updated, which causes all connect-ed components to get new props (those defined in mapStateToProps during a store update.
If a connected component subscribes to a store field but the action doesn't change that field's value, it wouldn't re-render.
The rest follows regular React rendering rules. If a connected component's HOC wrapper subscribes to a store field that has changed, it will update and cause the connected component to re-render as well. You could implement shouldComponentUpdate in the connected component if you don't want it to re-render.
References:
https://github.com/reduxjs/react-redux/blob/master/src/components/Provider.js
https://github.com/reduxjs/react-redux/blob/master/src/components/connectAdvanced.js
I'm working on a new React/Redux code base. I have a component connected to Redux through a container component. Basically, there is a piece of data within the store that has an id. That id corresponds to a conversation that needs to be loaded. When that number changes, we have a new prop. The component re-renders. And the componentDidUpdate method SHOULD be called... except it is not.
Again:
New data comes in (I have confirmed this with a console.log)
Component re-renders (I have confirmed this with a console.log)
...but componentDidUpdate is not called. I need it to be called.
I looked in Redux state, and the state changes. But there is no difference in Redux tools. I can visually see the data changing in state, but redux tools detects no "difference." AKA, even though the raw data is changing, the system does not detect it.
Could this happen if a reducer returns a mutated, original copy of state rather than a new copy?
I'm not sure it is default behaviour or redux or something else but i found that on dispatching an action, this action traverse through all reducers(that's ok) but it also invoke the connect listener of every reducer that further resulting rendering of its component. This means on every dispatch, all component inside app state tree get rendered. Is this intentionally done by redux or i've done something wronge.
Help me out to clarify this things.
In Redux , your state is global and handled by the redux, whenever you dispatch an action , you are just setting the global state. Your container comonents will receive the new state and reducer would work on them but your components wont be rerendered since previous state and next state would be same.
Only those components would be rendered whose mapStatetoProps result in a different result
This behavior is totally fine. See the React Docs for their virtual DOM concept:
React makes use of a virtual DOM, which is a descriptor of a DOM subtree rendered in the browser. This parallel representation allows React to avoid creating DOM nodes and accessing existing ones, which is slower than operations on JavaScript objects. When a component's props or state change, React decides whether an actual DOM update is necessary by constructing a new virtual DOM and comparing it to the old one. Only in the case they are not equal, will React reconcile the DOM, applying as few mutations as possible.
So you don't have to worry that every component will get re-rendered every time you dispatch an action.
So i'm fairly new to React and I can't wrap my head around a concept on how to re-render a main component based on another component.
Lets say we have a to-do application and a to-do item can have a state (new, running, closed). We are displaying all to-do items in a list and we can filter the items based on their state. We are using a bootstrap dropdownbutton like component to set the filter, which is a React component. Now when we change the filter we obviously want to refresh the to-do items.
My question is, does the logic of the selected state belong in Flux/Redux or does the filter component just say "refresh your items" to the main component?
When you use Redux in React application, follow one simple rule - all your components are stateless (means, no component initializes its state or calls .setState() anywhere).
The redux way of design based on state container, one big object that holds all application state. As React component, being connected to Redux store, Redux will pass the state (or portion of it) into that component, as this.props.state property.
That high-order component (or smart component), renders its children components (or dumb components) and handles events from them.
If child component requires change, it triggers corresponding handler (which typically passed as props). The only way to change the state is to dispatch an action. That action contains a type and a payload and based on that type, corresponding reducer is selected. The reducer then produces a new state, based on previous state and action payload.
If in the result of reducer call, state got changed, Redux will re-render high-order component, passing new state in properties. So, all child components will be updated correspondingly.
Check this example and trace how AddTodo component calls .handleClick() and then upper to .onAddClick() which dispatches an action.
If you are using redux, then on your dropdown you should have an onchange handler that dispatches an action every time the value is changed with the selected state (new, running, closed).
Redux reducer will handle this action by changing some state accordingly in the store for example: display = 'completed'. In addition to this, your todo list should also be stored in the store and it will likely be an array.
Your react component should receive a the todo array and display as props, and therefore everytime any prop (todo array or display) change, it will trigger a re-render.
In this case, your component should only display those todos that are complete (i.e. in the render you check if the state of each todo === this.props.display.
So to answer your question: redux keeps the state of the dropdown, which is passed to your main component, your main component then render only the todo's that matches the criteria.
So in a very minimal way, you could pass a function down to the select box, which calls setState on the top-level component. When that state changes, it will re-render its child components. This pattern doesn't scale well, and leads to the same hell React + Flux is trying to get us away from (state everywhere). I would say, using Flux (or even better, Redux), trigger an action that sets the filter in your store, and use derived data based on the filter state + your list of todo's in the todo list.