When you create React components, do you mostly follow the philosophy of only having dump/presentational react components that are connected to Containers? Only having dump components fulfils one of the main principles of redux (single source of truth) but complicated things when it comes to component isolation. By that i mean that:
... i end up have a table component which can present data and have the ability to select rows, but selection don't work unless its connected to the store via a container. This is good in theory because a lot of other components rely on that selection so having everything going through the store keeps everything in sync. However, it means that the table component cannot be fully interactable by itself (selection won't work if its not connected to the store). This could make automated UI tests slightly harder to test as each component will need to have a related container in order to work properly.
Another example; say that you have a dialog box, would you have the show state within the component itself or have it connected to the store through a container?
Any thoughts?
I personally like the Presentational and Container Components approach. It make the code clearer, cleaner and way more reusable.
The idea behind it is that your Presentational Component MUST NOT perform any action on the data, it is purely UI. And this data must come from your container (from the Redux Store, or from an helper class etc.)
The best practice is to pass down your Presentational Components functions from your Container Components via props.
// Container Component
handleChange(e) {
this.setState({ username : e })
}
render() {
return (
<Boarding
placeholder={this.state.placeholder}
error={this.state.error}
onChangeText={this.handleChange}
name={this.props.FB_user.user_firstname}
ProfilPicture={this.props.FB_user.user_picture} />
)
}
export default connect((state) => ({
FB_user: state.statusLogin,
}), {})(BoardingContainer)
Here is a simple example on how you can pass a function down your Presentational Component (which is TextInput here) and get connect to it to get back the data inputed in the TextInput.
Also, if you watch closely you'll see I pass this.props.FB_user.user_firstname && this.props.FB_user.user_picture that comes from the Redux Store that I connected to using the last lines of the code example.
Here is a very famous Medium article to get more details : https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.smfbi5hjj
Hope this helps, if you have any more questions, ask me.
Related
So basically I have an app with a single component tree. App as a parent and then it goes down from there. Initially, all of the states are obviously centralized from the parent component App, as it is normally, and then the state is passed per component via props. We all know this is a hassle as the component tree gets bigger and bigger.
I'm studying React-Redux and just curious if I always have to use connect() and then each create a mapStateToProps and mapDispatchToProps for each and all my components including the subcomponents? Is there a one-off way to do this? Isn't it possible for my many components to just access the entire store without mapping each state/dispatch to props one-by-one, which I find repetitive and time-consuming?
I came from a Vue-Vuex background (although my Vuex experience is limited) and React-Redux is just a whole different ball wax, if not quite a lot more complicated IMO.
Per the Redux FAQ entry on "Should I connect all my components, or just one?":
Early Redux documentation advised that you should only have a few connected components near the top of your component tree. However, time and experience has shown that such a component architecture generally requires a few components to know too much about the data requirements of all their descendants, and forces them to pass down a confusing number of props.
Emphasizing “one container component at the top” in Redux examples was a mistake. Don't take this as a maxim. Try to keep your presentation components separate. Create container components by connecting them when it's convenient. Whenever you feel like you're duplicating code in parent components to provide data for same kinds of children, time to extract a container. Generally as soon as you feel a parent knows too much about “personal” data or actions of its children, time to extract a container.
In fact, benchmarks have shown that more connected components generally leads to better performance than fewer connected components.
In general, try to find a balance between understandable data flow and areas of responsibility with your components.
With Redux you don't have to connect all the components to its store. You only connect the components that really need it. For example, if a connected component has children then it might be simpler not to connect the childeren to Redux but rather let the connected parent drive the updates for its children. Grandkids can be coonected but not their immediate children and so forth. There can be many approaches and every component can still have its own private state in addition to Redux store.
Currently React.FunctionComponents are in fashion and you can use useReducer hook instead of connect though you will have less possibilities to fine-tune for performance with the hook.
Your state in redux store doesn't change, but in order to use it, you should use connect and connect to your store.
If you don't want to use connect,
you can simply pass your states to a child component by props like
<mycomponent data={this.state.data} />
And use your data in your child component
If these ways not satisfying you can read about the context system, but it's parent to the child again, but you can pass data from parent to grandchild without using child
You can read about it here
Hope this helps you.
After a lot of search and working with React and React Native. I still have a pretty vague opinion on which
is best to use and in what situations
Having the parent component be connected to the store and passing as props all data to children functional components. This what I initial though was the "React" way but pretty soon I saw that as the app grow the amount of logic handled by this parent component starting too be to big and messy.Also child components start to have children of its own and so on and so forth.
Having parent component (Screen for example) that is functional and each child that needs information from the store will be connected to it. This is much more "clean" solution but will create a lot of store connection "duplications" which are not necessary.
Using Redux store
My question in general which is more recommended pattern to use and in which use cases, also would be nice to know what is the price for having a lot of connected (containers) components
Not sure i can provide a right or wrong answer for this question as each has its pros and cons.
My rule of thumb is to connect deeply nested components only when their parents are "proxies of props". That is they accepts props only to pass them down to their children.
If i may quote (myself) from this answer:
Avoid connecting components when you can and pass down the props to
the children, the main reason for this is to prevent dependency on
redux. I prefer keep my components "dumb" as i can and let them
concern only on how things should look. I do have some components that
concern on how things should work and these components are mainly
dealing with logic and passing down data to the children, they are the
components i often connect.
When i notice that my app is scaling and some of my components are
acting as a proxy of props (i even got a word for that! "Propxy"),
that is they get props from their parent and pass them down without
using them, i usually inject a connected component in the middle of
the components tree so i can let the "propxy" components down the tree
flow be more lighten and slim
You should also note that one more pitfall with connected components is that each render will trigger the mapstateToProps method. if you got some heavy logic there you should memoize it, usually done with reselect
As for the benefit of connecting a component, well you probably realize that already. you get quick access to the Provider's state via react's context.
Edit
As a followup to your comment:
about the rendering - wont I have much more unnecessary rendering if Ill have a deep nested children (common in medium to large apps) that will be unnecessarily re rendered on each parent update
Well the connect HOC wrapper won't trigger a re-render if the previous object of mapStateToProps is the same as the current object returned. so no unnecessary re-renders to your connected component will take place.
You can read in more details on how it works and how the logic was evolved over time in this article
I use the first option.
The cons you wrote are correct, but i think its easier to debug and understand the data flow this way.
Don't connect a component to redux if the current component doesn't use this data from redux and only passes.
If the component uses data then connect to redux.
If the current component uses data from redux and the next component also uses it then you can pass and don't need to connect the next component to redux.
MAIN RULE:
if there is a gap in the data usage chain from parent to child then don't need to pass data from parent to child
connect(parent) (don't use props) => child (don't use) => child (don't use) => child (using) - better to connect last child. Isuue related to props dreeling
Say I want to create a little editor for my software that helps me organise people in my company. I will use React & Redux. The editor is a React component (or maybe container?), and it shows me one person at a time. I can edit things about this person, delete fields, etc. and when I am ready I can click a button which will then give me the next person to edit.
Now, I am quite new to React still and can imagine doing this in 2 ways:
Solution 1: Decouple the editor component
Create an Editor Component, which takes an array of all the people in my company. I do have these people saved in the Redux state of my app, but the editor component will not work on my Redux state, but do all changes in its internal state first, and only once I click save will the Editor component commit these changes to my Redux state. This might be a problem, and changes could get lost if somebody doesn't save their edits.
The advantage here is that I have my Editor de-coupled from the rest of my App, and the logic of the Editor will stay in that component.
Solution 2: Connect the Editor Component to Redux
Here, I would connect my Editor component to Redux. So I would not give my component the people array, but direct access to the my Redux store via selectors (for example). I would also not have a deletePerson() function internal to my component, but pass this down as a prop into my component (and it would presumably be a Redux action). This way my component would work directly on state, which I can see as having advantages.
But taking it out of this app and reusing it somewhere else would get more and more difficult, the more complex my component becomes.
Please remember that I am a beginner and that these two solutions are what I came up with as a response to a problem I am facing in my own application. However, I would appreciate if you could help me out here, and explain to me how I should think about problems like this. Is there maybe a third solution I am not mentioning? Or am I misunderstanding a concept?
Personally, I am inclined to go with Solution No. 1, but I also know that the whole idea of Redux is to keep state in one place. What would you advise? Are there performance differences / advantages with one solution?
Your first solution is good but why not use a service when its provided?
You should try to mix up features of Redux React. First, separate your presentational and container components and in one of your container component pass the props directly to redux store on click,etc. Then use redux actions to access the store like deleting,etc. Provide a UI using React presentational components for data entry and pass this data to redux store. Use redux actions when you think they will be useful and not destructure your app.
Go to https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0 for further details on how to connect presentational and container components.
Before proceeding, I'd like to point out that the title of this question was rather difficult to phrase. If a more suitable title should be used, please let me know so that I may change it and make this question more useful to others.
OK, on to the problem… I am currently working on a React/Redux project. A design decision I made was to manage app state and UI almost entirely with (hierarchical) state machines, for a number of reasons (which I won't delve into).
I have taken advantage of Redux to store my state tree in a substate called store.machine. The rest of the Redux substates are then responsible for storing app 'data.' In this way I have separated out the two concerns so that they don't cross boundaries.
Extending from this, I have also separated concerns on the (React) side – using 'state components' and 'UI components.' State components deal almost entirely with the flow of state, while UI components are those components that get rendered on the screen.
I have three types of state components:
Node: This kind of state component deals with state branching. It determines which component should be rendered based on its current state (a form of delegation).
Leaf: This kind of state component exists at the leaves of the state tree. Its job is merely to render a UI component, passing along the necessary 'dispatch' callbacks responsible for updating the state tree.
Container: This kind of state component encapsulates a Node and UI component to be rendered side-by-side.
For my circumstances, we're only concerned with Node and Leaf components. The problem I'm having is that while the UI components are being rendered based on 'leaf states,' there may be scenarios where 'higher-level' states could factor into how the UI should be rendered.
Take this simplified state structure:
AppState starts off in the Home state. When the user clicks the login button, a to_login action is dispatched. The reducer whose duty is to manage AppState will receive this action and set the new current state to Login.
Likewise, after the user types their credentials and validation is done, either a success or failaction would be dispatched. Again, this gets picked up by the same reducer who then proceeds to switch to the appropriate state: User_Portal or Login_Failed.
The React component structure would look something like this:
Our top-level Node receives AppState as a prop, checks what the current state is and renders/delegates to one of the child Leaf components.
The Leaf components then render the concrete UI components passing along callbacks to allow them to dispatch the necessary actions (described above) to update state. The dotted line represents the boundary between 'state' and 'ui,' and this boundary is only crossed at Leaf components. This makes it possible to work on State and UI independently, and is therefore something I would like to maintain.
Here is where things get tricky. Imagine for the sake of argument we have a top-level state to describe the language the app is in – let's say English and French. Our updated component structure might look like this:
Now our UI components would have to render in the correct language, even though the state describing this is not a Leaf. The Leaf components that deal with the rendering of UI have no concept of parent states and therefore no concept of the language the app is in. And thus, the language state cannot be safely passed to the UI without breaking the model. Either the state/UI boundary line would have to be removed or parent state would need to be passed down to children, both of which are terrible solutions.
One solution is to 'copy' the AppState tree structure for each language, essentially creating a whole new tree structure per language… like so:
This is almost as bad a solution as the two I described above, and would need an escalating number of components to manage things.
The more appropriate solution (at least when dealing with something like languages) is to refrain from using it as a 'state' and instead keep some 'data' about it. Each component can then look to this data (either a currentLanguage value or a list of messages pre-translated in that language) in order to render things correctly.
This 'languages' problem isn't a very good example because it can be structured as 'data' rather than 'state' quite easily. But it served as a way to demonstrate my conundrum. Perhaps a better example is an exam that can be paused. Let's take a look:
Let's imagine the exam has two questions. When in a 'paused' state, the current question gets disabled (i.e. no user interaction can be done). As you can see above, we need to 'duplicate' leaves for each question under Playing and Paused so that the correct state can be passed along – something that is undesirable due to the reasons I mentioned before.
Again, we could store a boolean somewhere that describes the exam's state – something that the UI components (Q1 & Q2) can poll. But unlike the 'languages' example, this boolean is very much a “state” and not some piece of “data.” And so unlike languages, this scenario demands that this state be kept in the state tree.
It is this kind of scenario that has me stumped. What solutions or options do I have that could allow me to render my questions while utilizing information about our app's state that is not contained in a Leaf?
Edit: The above examples all use FSMs. In my application I have created some more advances state machines:
MSM (multi-state machine): Container for multiple state machines that are active simultaneously
DSM (dynamic state machine): A FSM that gets configured at runtime
DMSM (dynamic multi-state machine): An MSM that gets configured at runtime
If either of these types of state machines can help to provide a solution to my problem, please feel free to let me know.
Any help is much appreciated!
#JonasW. Here is the structure utilizing an MSM:
Such a structure still wouldn't allow me to get the 'pausable' state information over to the questions.
Let's try to propose a solution for your architectural problem. Not sure if it will be satisfactory since I am not fully confident in my understanding of your problem.
Let's take your problem from the point you start having real problems, the Exam component tree.
As you stated, the problem is that you need to replicate your leafs in each possible 'Node State'.
What if you could make some data accesible for any of the components in the tree? For my this sounds like a problem that could use the Context API that React 16+ provides.
In your case I will create a Provider that wraps my whole application / Branch of the tree that I am interested in sharing a context with:
In this way you could access your context from any of the components and it can be modified dynamically and through redux.
Then is just left for your UI Components to keep the logic to deal with the UI State provided or computed with the given context. The rest of the application can keep it structure without complicating the lower levels or duplicating nodes, you just need to add a wrapper (Provider) in order to make the Context available.
Some examples of people using this:
Material UI <- They pass the theme as a context and access it whenever and wherever (The theme can also be change dynamically). Very similar to the locale case that you showed. WithStyles is a HOC that links a component to the theme in the state. So that simplified:
ThemeProvider has theme data. Under it there can be Routes, Switch, Connected components (Very similar to your nodes if I understood right). And then you have components that used with withStyles have access to the theme data or can use the theme data to compute something and it is injected in the component as a prop.***
And just to finish I can draft kind of an implementation in few lines (I didn't try it out but it is just for explanation purposes using the Context explanation):
QuestionStateProvider
export const QuestionState = React.createContext({
status: PLAYING,
pause: () => {},
});
AppContainer
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
status : PLAYING,
};
this.pause = () => {
this.setState(state => ({
status: PAUSE,
}));
};
}
render() {
return (
<Page>
<QuestionState.Provider value={this.state}>
<Routes ... />
<MaybeALeaf />
</ThemeContext.Provider>
<Section>
<ThemedButton />
</Section>
</Page>
);
}
}
Leaf - It is just a container that gets questions from the state and render a question or more...
Q1
function Question(props) {
return (
<ThemeContext.Consumer>
{status => (
<button
{...props}
disable={status === PAUSED}
/>
)}
</ThemeContext.Consumer>
);
}
I hope I got your question right and that my words are clear enough.
Correct me if I understood you wrongly or if you want to discuss further.
*** This is a extremely vague and general explanation of how material ui theming works
I have a question about how to structure a React/Redux app.
As far as I understand, it's not recommended practice to reference containers inside a component. However when nesting components withing a Redux app, the top level container is bound with a connect() and mapStateToProps etc, but it seems strange to pass in all props down the line to -only- components.
When structuring an app with a nested component for example like:
Dialog > Form > Tab > Input Section > Input control
the input control could have a prop isVisible, where it seems strange to me that I would have to pass the prop all the way down the tree.
So my question is mainly, is this indeed what is recommended and how is this handled? Is this for example simplified by setting props to something like:
{
inputProps: { visible: false }
}
?
Or, can I reference a container inside my component, so I can have a separate connect() for only the props actually relevant?
One of the main points of Redux is to allow individual components to connect to the store and extract the data they need. Also, don't overthink the whole "container/component" distinction in terms of separating things in the codebase.
See the Redux FAQ entry at https://redux.js.org/faq/react-redux#should-i-only-connect-my-top-component-or-can-i-connect-multiple-components-in-my-tree for more info on connecting multiple components, and Dan Abramov's tweet at https://twitter.com/dan_abramov/status/802569801906475008 for thoughts on "container vs presentational" structuring.
If you find yourself passing down many properties, maybe they should be containers.
Just take redux-form as an example. It could perfectly be all about components, but they decided to use redux as well.