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.
Related
I have a form component which now receives an onSubmit handler via its props, so it is not attached to state directly.
Before calling onSubmit, the component validates itself and generates errors. Now I'm wondering if this component can still be considered presentational, since it's doing some 'smart' work in validating the data.
I don't think you need to worry about this too much. "Containers" is just a naming convention people use for react components that are usually "connected" to a store.
Keep your validation inside the same form component so everything regarding that form is encapsulated and nothing leaks outside of it. As you stated yourself, the component isn't connected to state directly. The parent component shouldn't care about validation, all it needs to know about is the returned value/object from the onSubmit handler.
Reading many articles and blogposts on this I understand(simplified)
mapDispatchToProps()(
clickHandler: ()=>dispatch(Action)
);
<Component onClick={this.props.clickHandler} />
Does the same as
<Component onClick={store.dispatch(action)} />
Which looks simpler than having all the hassle of using mapDispatchtoProps
I am new to redux and react in general and can't wrap my head around this. Is there an actual necessity to use it or is it just good coding practice?
There isn't an absolute necessity to use mapDisplayToProps but it will get pretty handy if your application grows.
In your second example you access the store object directly. This is not considered a good coding style because you couple your component to a global object which makes it harder to test the component in isolation or to use it in another context.
Think about each component as an isolated piece of software with the props passed to the component being the only interface to the rest of your application. This won't matter much for small example-like applications but pays off in real-world conditions.
The main idea of connect with mapDispatchToProps and mapStateToProps is to keep you UI components simple and easily reusable. Imagine, if you have 3 applications which have completely different architecture(redux, flux, pure React ContextAPI), but should reuse same UI components. If you incapsulate business logic directly to your components (2. example), then it might be very hard or even impossible to reuse it, because it is attached to some store (in the place where you use your <Component ... />).
Just as a side note and good example, how mapDispatchToProps can make your application clean is clear separation between business logic and UI component.
Example:
You have a Button component, which is used all over the application. Then you get a requirement that you need to have a logout button in different places of your application. One way would be to create a new regular React component, which will use the Button component inside and also have some logic.
connect with mapDispatchToProps comes to help you and allow to easily create a new LogoutButton component with attached logic (which also allows you to update the redux state), then whenever you need to have a logout button you simply use LogoutButton and there will be no need in any extra logic because it's all defined inside mapDispatchToProps and is already attached to the Button component.
mapDispatchToProps() is a utility which will help your component to fire an action event (dispatching action which may cause a change of application state)
This is a bit complicated so I'll try to put it as simple as possible.
I have a pretty much complicated reusable component in my app.
Basically, it is a large table with many editing options.
Since this component should be reusable, my thought was that it should manage it's own state.
It also makes sense because this component's business logic is pretty much complicated, and by using redux, I'll probably have to repeat some crazy boilerplates.
On the other hand, this component should be able to have some default data loaded to, and finally, this component is in some cases a part of a form, so I sohuld be able to extract it's data and send it to the server.
Redux can really help with the last two tasks - if I had an easy way to store all component changes in the store, I could easily load the default data from there (because my component will be fully controlled), and it will also be easy to extract data from the store when sending to server.
Although, it has a lot of boilerplate, and I'm not feelinng comforotable to write a componenet specific logic in my reducers, since ideally, they could manage themselves.
Any more ideas about that?
I had one idea that seems to be working, though I am not sure how good it is:
Have a "dataKey" prop to handle default data prop changes, and derive the state from the data
Use some submit callback to extract the data and send to server
Any more thoughts will be very helpful, thakns!
It's hard to provide an extract answer as your question is kind of abstract. But since you are just looking for ideas, this is just an idea which you can try to incorporate with the actual use case.
In this kind of scenario, I would first distinguish my actual data and UI state. Then I will write my component as a controlled component of actual data with the usual value and onChange props. The UI state will be kept in the internal state of the component and it will either be derived from the initial props or initialized with a default value. When the user interacts with the component, if the change affects only the internal state, we can just use setState to update the state. If it affects data also, we can fire onChange prop also accordingly. This way we can keep the actual data in the redux store, but still, keep component specific logic in the component.
As an example, let's say we want to make a text label component with in-line/in-place editing support. I would still keep the props of this component similar to the default HTML input element as value and onChange. But the flag that indicates whether to render a text or input element with 'Submit' and 'Cancel' buttons will be kept in the component as isEditMode. Initially, we can always keep isEditMode as false. But when the user clicks on the text, we change it to true, so that component will render elements for editing and hide the label. While the user changes the text we can keep that intermediate value also in UI state. But when the user clicks the 'Submit', we can fire onChange with the new value in state and change isEditMode also to false. Likewise, we can keep the component as a control component but still use the component state to manage intermediate UI states.
Hope this helps!
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.
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.