I've got a React/Redux application where I have a number of global commands that can be called in various ways - via context menu, via shortcut, or by clicking on a button.
These commands are then handled in the place relevant to the command (for example if the command is "save", it is handled by the text editor component).
So far I've done this in a convoluted way:
I dispatch a "COMMAND_EXEC" action like so: { type: "COMMAND_EXEC", name: "save_note" }, which in the reducer populates a state property "current_command"
Then in the component I map this current_command state property to a prop
Finally in componentWillReceiveProps, I check if there's a "current_command" property and handle it.
Once it has been handled I clear the command with a different Redux action "COMMAND_CLEAR"
It kind of works but it's over complicated and I suspect it might cause issue as there's more and more components and commands. And I guess I'm using Redux actions as events, which is probably not a good idea.
So I'm wondering if there a more proper way to handle these kind of events in Redux?
The answer would depend on what these commands are expected to do:
Are these commands doing UI updates which are very tightly dependant on state of the component?
Are these commands making an api call / navigating to a different route etc?
Case (2)
The View (React Component) should not be the ideal place to execute this command. Rather, you should execute the command as an action. The text editor component should dispatch an action "save" which is handled by redux. Any other XYZ component can also call the same action "save". If the action requires the current state of text-component, you should maintain this state in a reducer.
Case (1) -- UI Updates
It is not a very good idea to keep UI state in a reducer unless required. But at times, you would need to do it. See the following example:
You have a switch which turns "off" and "on", the Switch Component should be the ideal place to keep its own state.isOn. When updated, it would let its parent know by this.props.onUpdate.
Now, what if an external action wants to flip the switch? The best way to do that would be to lift the state of Switch Component up to a Parent level and let the parent handle everything for the Switch Component.
Read: Lifting State Up - React
Similarly, you would "lift the state" for your UI Component to reducer and allow actions to modify the state of your redux store. The View components would simply listen to store updates and re-render accordingly.
What you are supposedly doing is:
The React Component manages its own state
Its state can also be changed by an external command to which it listens using componentWillReceiveProps
which will make the application messy and difficult to manage.
The possible solution:
Actions should be the place where global commands are actually executed
Reducers should be the place to keep application state required to execute these global commands
These global actions could be dispatched from anywhere in the application
The result of these global actions would again be stored in a reducer which the UI Components would listen to and update themselves.
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
Let's suppose I have a Modal component that triggers an MODAL_CLOSE action when the user closes it.
Let's suppose I have an application that uses Modal component in many different places and, in some cases I want to change the application store when the MODAL_CLOSE event is triggered.
Is it correct to have, say a user reducer that listens for the MODAL_CLOSE action to make any change to the user portion of the store? Or by doing this I'm actually creating a coupling between the user "domain" and the Modal component?
What's the best practice in this case?
I'd say it's fine, because it's not coupling with the component, the connect call is doing the coupling.
Your reducer doesn't depend on the implementation of the component or even the existence of the component, just that there is an action MODAL_CLOSE(D?).
Likewise, your component is not coupled to or aware of the logic of the reducer.
I think it's correct. You would use something like <Modal onClose={closeModalAndDoSomethingAction} in the places where closing it has special behavior. The Modal component could then either dispatch its default onClose action, or the special one, if provided via prop. The special action would either be something other than MODAL_CLOSE or maybe have something in the payload that the reducer needs to make a distinction.
I'm working in a project to to replace a large Silverlight application with a web application using react (and redux). There's multiple tabs and subtabs that the user can jump between.
We are using redux to save tab/subtab-state. The current solution uses cloneElement to inject previous state and a function (onSaveState) that all components needs to call in order to save state.
Is there a way to avoid having the save/load boilerplate code in all pages on the tabs+subtabs, for example by getting the state of a child component?
An ugly solution is to save the entire component (including the state) but this introduce a lot of overhead + having the react virtual DOM handle something that is not actually rendered may lead to several other problems.
Note: We are not allowed to change the overall UX.
Update: What we want to accomplish is to make save and load of state as simple as possible when the user jump between open tabs. A user can open several tabs of the same type. Most tabs have undo-functionality. It's a large application with 150+ views (not counting all smaller dialogs). To make the save/load of state from the redux store as seamless as possible it would have been nice to inspect the state(readonly) of a component (from a parent) just to save it. We have an ok solution today as I mentioned where we get the previousState as a prop and we call onSaveState on componentWillUnmount with the current state. I don't need an explanation of how redux works, I'm simply interested if it's possible to inspect the state of component from the outside (for example from a parent component) in a way that is not to hacky?
If you have complicated save/load code, don't put it all in the parent component and inject it into the children. Move it into shared files that the children can consume on their own.
Put loading code in a reducer file. Put saving code in an action file. Then let the tab components each require the new files so they can connect to the reducer and dispatch the action.
See Redux Basics for a thorough example.
The web is full of people telling me I'm doing react wrong. I'm sure they're right, since I've just started. A commonly referenced truism is that react is just the view layer. That's wonderful, but it leaves me wondering simply where do I put my other stuff?
I have a pretty straight-forward set of components which together show a list of nested data types and allow some editing, creation, and removal of the things. The components which consume the data have it passed in through props down the hierarchy from a parent that fetches the data. Should those read operations go somewhere else if it's "just the view layer"
What's the best practice for this, the idiomatic way, the react way? Should my delete operation be included with my delete button component? next to the read operation? somewhere else?
I suggest you to try some flux architecture. In this case it will looks similar to described below:
You call action on delete button click, for example actions.deleteUser(1)
Action calls appropriate API
Store connected to your component changes and component state changes
component re-rendered automatically
It depends on Flux that you prefer. The flow may be slightly different. I prefer reflux one
In react, data flows only from parent component to child component. I assume that your state is stored in the parent component, since you have create, update and delete in separate components. The state can only be changed by calling the setState() function on it. Therefore child components cannot modify the state of the application. This can be done only by having a callback function.
The delete function will be written in the parent component and will be passed to delete component as a prop. The delete component will then call the delete function (callback) which will call the setState() upon the state of the parent component and thereby altering the state. Never alter the state of the application without setState().
Hope this helps
I've converted most of my containers to functional components to make them reusable and I'm wondering if it's good practice to pass Action Creators as props to theses functional components.
In this case, I'm using a tab to switch between Login and Sign Up page and I'm using local state to manage active class (for styling). I call action creators passed down as props to switch between rendering a login or sign up page. I'm using this tab in several places and I'm passing a different configuration object as per use cases.
homePageTabProps = {
firstTabTitle:"blog",
secondTabTitle:"resume",
showFirstTab: this.props.showBlogTab,
showSecondTab: this.props.showResumeTab
}
Is this good practice? yay or nay?
Edit:
The active tab style is giving me problems (retains value when reusing the component). Can I have local & global state? (Sorry if this sounds stupid.)
Passing functions as a props down the hierarchy of your Components is for sure widely accepted practice. But I would suggest not to pass bare action creators, but bind them to dispatch before passing them to Component. This way, if your child Component is not connected to store it will not have to know about Redux at all (no need to manually dispatch).
As for your complication with two states. There is nothing wrong in mixing own Component's state with part of Redux passed to Component via connect. I would even strongly recommend to keep all temporary data not important to your application logic inside Component's state without exposing it to Redux. For example, most of the time, there is no sense in sending animation timings, intermediate state of user input, etc. to Redux.
But, in your case looks like indication of active tab is a direct reflection of Redux state and should be fetched from store. Otherwise it's not clear why you are sending actions to Redux on tab's change.