I have 3 components in a html page.
A,B,C
By the PSD desgin ,in the DOM level , A includes B and B includes C.
so in the React level , I'd like to design component tree as follow:
A(stateful component) ->B (stateless component) ->C (stateless component)
I will make A redux-aware by connect method and hand down the redux state to B then -> C.
However many guides recommend that a stateful component can only contain stateless components whereas there's no mentioned whether:
1. a stateless component can contain another stateless component?
2. a stateless component can contain another stateful component?
3. a stateful component can contain another stateful compoent?
so anyway ,how to design my components, thanks in advance!!
A(stateful component) ->B (stateless component) ->C (stateless component)
both B and C expect the state from A to pass down to them.**
Some times you can learn more my reading example code, take a look at this example Todo List provided by redux it clearly shows that MainSection contains TodoItem and a Footer both of which are stateful and MainSection itself is stateful. A major example may even be the Material-UI library which is all stateful components and you can use it with stateless or stateful components.
There is no reason stateless components can't contain state-less components and there is no reason stateless components can't contain stateful components. An example of a stateless component containing stateful components is literally your top level App or index file at times. If the repo linked above, take a look at App.js.
The main concern with stateful components containing stateful components is a lot of needless updates to your UI. These are some times not obvious because the shadow DOM diff's against the DOM and makes the appropriate changes, but there is non-the-less a cost to the diff and the operation is triggered every time your state changes.
A good way to solve this issue is to keep your components fairly flat in their dept or to implement the shouldComponentUpdate function as needed.
Having state in your components just makes things easier to manage due to separation of concerns, so I find it hard to believe using them under stateful or stateless components could be an issue. Stateless components will render every time the component that contains them renders, so perhaps the issue of embedding stateless components inside stateless components is one of depth, i.e. the deeper your DOM the more complex the diff operations (purely guessing based on experience) so the guideline discourage this so that you can keep your tree as flat as possible.
Honestly, I don't see any of this being a problem as long as you use good coding practices and are aware of the consequences of your decisions.
Related
I'm struggling about what may be a good way to implement components in React with a good coding pattern.
Normally I know the idea of presentational and container components: the presentational only shows html and receive everything from props (data and callbacks); the container orchestrate the presentationals retrieving and mutating data and passing it to them by props.
Now I'm using redux with redux toolkit and rtk query, with hooks.
Following that approach, the container component should be the only one allowed to useSelector and useDispatch and useQuery. But I find a lot easier and cleaner allowing the presentationals to select and fetch and dispatch what they really need, instead of making a giant container component which manage all the data for its children with a huge list of state and fetch access. This is true especially for lists, where it is a lot easier and cleaner just letting each child to retrieve its own data (fetched or from state), or for deeply nested presentationals.
However I'm mixing up container components with fake presentationals which anyway retrieve something when it is easier and true presentationals maybe for general and totally reusable components. Also the components tree is very messy (like container->fake presentational->container->fake presentational->true presentational->true presentational ...).
At the end I feel like I don't have good rules and the code is messed up.
Are container and presentation components still a good coding style which follows a best practice pattern but in the world of hooks and redux?
The React Container Pattern advocated by Dan Abramov has for all intents and purposes been deprecated since the introduction of React hooks in 2018.
See Dan's blog entry Presentational and Container Components from 2015.
His update from 2019:
Update from 2019: I wrote this article a long time ago and my views
have since evolved. In particular, I don’t suggest splitting your
components like this anymore. If you find it natural in your codebase,
this pattern can be handy. But I’ve seen it enforced without any
necessity and with almost dogmatic fervor far too many times. The main
reason I found it useful was because it let me separate complex
stateful logic from other aspects of the component. Hooks let me do
the same thing without an arbitrary division. This text is left intact
for historical reasons but don’t take it too seriously.
With the advent of React hooks the distinction between "smart" and "dumb" components, and "container" and "presentational" components, was all but eliminated.
The common pattern and "best practice" now is to write React Function components and just use the React hooks. In the case of using Redux and React-Redux, the useDispatch and useSelector hooks instead of the connect Higher Order Component. I've not gone out of my way to write a React Class component or split my code between "presentation" and "container" since the advent of React hooks.
My rule of thumb is to do it all in one component. Then as you create more and more components you'll see patterns start to emerge. So instead of copying and pasting code from component to component you can make a presentational component that takes in props for what to render. Some of those props can even be what to do when a button is clicked or a box is checked.
Overall your presentational components will end up resembling something like one of the various react js ui frameworks out there such as https://mui.com/
Let's say that I'm fetching some images from an API in the App component.
Then I want to pass it to the component responsible to rendering images. But this component is not a direct child to the App component. It is the child of a direct child of App component.
Here's how I would pass the images array down to the image component, but I feel like it might not be the best approach.
But what would happen if this hierarchy gets more complex - even just by one more component:
Intuitively, it might not be the best thing.
So, what would be the best way to pass the images array down to the image component, if there are many other children between them?
The problem is usually called Prop Drilling in the React world: https://kentcdodds.com/blog/prop-drilling
A few options:
Passing props may not be that bad. If the app is small, is a very modular -and easy to unit test- option . You can reduce the verbosity by using prop spread: <Comp {...props} /> and by keeping your component interfaces similar. (many people dislike prop spreading as you can unintentionally pass unsupported props, but if you use TypeScript the compiler will catch that).
You can use a React Context: https://reactjs.org/docs/context.html (as other mention in the comments). However, keep an eye on how your context objects are defined (keep them small). React will re-render all the childs using the context when the value changes, is not smart enough to automatically detect changes at the property level. Frameworks like Redux or Zustand use other mechanisms to allow a granular control of the shared state (you'll see examples of a useSelector hook).
You can also take a look to a state management framework (Zustand is my favorite, but Redux is more popular). However, it may be an overkill for small things.
My personal choice is to start with prop drilling, it's easier to modularize and unit test. Then you can think on your app in layers: upper layers depend on a context (or a state framework), and lower layers receive properties. That helps when you want to refactor and move reusable components to other projects.
I'm having trouble understanding when I should be passing props down to child components rather connecting those components directly to the state.
There are two ways that components in my project receive props:
1) Connecting a component (child or parent) to the global state of redux. This allows me to specify which parts of the global state my component will receive, but will re-render when a prop changes.
const mapStateToProps = state => ({
error: state.error,
progress: state.scan.progress,
latitude: parseFloat(state.enrollment.latitude),
longitude: parseFloat(state.enrollment.longitude),
});
export default connect(mapStateToProps)(MapViewHome);
2) Passing props down to child components in typical React-Native fashion.
<MapViewHome error={this.props.error} progress={this.props.progress} latitude={this.props.latitude} longitude={this.props.longitude} />
The reason I'm asking this is because I have parent component A which is connected to the state.
Parent component A passes prop x directly to child B which passes the same prop x to child C.
If prop x changes, this will cause components A, B, and C to re render. I could avoid the re rendering of components A and B by connecting child C directly to the state, so that it is the only component effected by the prop change.
But is it good practice to connect small child components to the global state like that? Why not just connect every component to the state?
This is a complex issue that the redux / react community discuss a ton.
You can probably find tons of Medium articles and React / Redux authors that discuss this.
But to give you a high level overview; If it seems like it's a pain to 'drill' props down from CompA -> CompB -> CompC -> CompD, store the data in redux.
If the data only needs to go from CompD -> CompE, you can pass it down as props.
You could store every prop that needs to be shared into redux as well. Just be aware of managing your redux object and try to normalize and manage the giant object.
Ultimately, it is up to you as the developer to make these decisions, as there is no silver bullet for this answer.
The main advantage of using stateless components is reusability. Using your example, a stateless version of MapViewHome could be used to display multiple maps of different lat/lngs on the screen at the same time since you can pass different props to each one. A stateful MapViewHome could only display one since it relies on global state.
So it's really up to you how to want to architect your components. I think it's a good idea to always start with stateless components but if your use case doesn't require reusability then using a stateful component is fine.
Typically, you don't need to use your store when you're capturing form data or if you're simply trying to hide and unhide elements. For example, you might want to have the local state change when you're typing data in a field and then you might use that local state to pass down to a thunk creator that you're dispatching. If you can provide a bit more context about what specifically you are trying to achieve here, I'd be happy to provide more guidance!
I know this might be a little opinion-based question, but I think an important one.
In short, is it good practice to have react container components inside a react presentational component? What would you say could be the benefits and disadvantages of this practice of having container components inside a react presentational component?
I think that presentational components should be dummy: They take in props, and behave according to them, and nothing else affects them. They behave expectedly when given certain props, and nothing outwhere should affect their behaviour.
What could be the problem then having container component(s) inside a presentational component? Well, as container components usually have access to the (global) store (in redux), you cannot know simply from the props of the presentational component, that how the component will behave. Because the store will affect to the behaviour of the container component, and as it is included in the presentational component, then the presentational component is no longer a dummy component. What do you think?
I assume that by presentational component you are referring to a ReactJS functional component?
If so, I do not see a problem with this approach. The resulting component wouldn't be purely presentational, but it would do the job of defining the composition of the component(s) it renders.
Depending on the context, this could be exactly regards you need.
Rather than trying to build an application starting with presentational components, I prefer to take the approach of first scaffolding the bulk of my application and then refactor what I need to into presentational components.
Im learning React and pondering over the structure of the components. The following has me confused a bit.
We are told that there should be a single source of truth.
The owner component should pass the props / states to its responsibility (as some call 'ownee') components.
So, if my own whole app is one big component (owner) with lots of its responsibility (ownee) components, does that mean that that top level owner component will hold ALL the props and states. That would be a massive object.
As Im not initially using states, any changes to props would have to be passed to the 'owner' & then that component rendered again?
Clearly this is not right, right? Any guidance would be much appreciated.
That interpretation is slightly off-mark. Your top level component doesn't need to be an all-knowing omniscient behemoth, simply because of the crucial difference between props and state. Any component is free to pick and control its own state, which it can pass down to its children. However, a prop for a component should not ideally be preserved in its state variable because that's what causes a duplicacy and violates the single source of truth paradigm. A prop is NOT owned by the component, it is owned by the ancestor which sent the prop down. On the contrary, it is natural and expected for a component to pass its state down as props to its children.
You will see that you can't do much without state, unless your app displays static content mostly. So when you start dealing with state, keep state where it belongs. Even with Flux there are ways to keep state relevant to the component to which it belongs.