In the React, is the Route and Container 1: 1? - reactjs

I think need your help.
Currently I am working with React.
I think in React, Container and Route are 1: 1. So when I do Router configuration with React. In a typical 'Redux' configuration, the Container(smart component) same to the number of pages in the route.
If I look at the implementation pattern of others, the Container does not just reflect the route.
Common There are many more cases than Route.
In the structure using 'Redux', is Container 1: 1 Route?
Also, Container does not seem to have an HTML Tag, is this correct?

This is not necessarily true, you may have a route that renders a component that doesn't have behaviour and because of that it'd still be a presentational component.
I'd recommend you to not get overwhelmed by the definitions of containers and component. Try to think a Route as just another component with the difference that when the path matches it will render the specified component (or in line function if you used the render property of the route.
Always start simple by creating components that are just functions which return content, and then as the requirements are changing start growing by declaring a class which extends Component and then start decoupling the returned elements into other components. Same thing with Redux, by default don't assume you always need behaviour/state so don't even connect the component and then start growing by adding state and then adding actions. But whenever you think your component has many responsibilities start the cycle again by decoupling into more components.

Related

Is it considered a bad practice to nest container component inside a presentational component? [duplicate]

I am new to react and redux. I have a scenario where there are nested components like this.
A > B > C > D
There is a property used in A component and it will be used in D component. So, I have two approaches:
Get state from redux store in component A and then pass it along as props to all it's child components even though it will be used only in D component.
I should connect to redux store in component D and fetch that property from there.
What is the correct approach?
As Dan Abramov, author of redux says in this issue
Both approaches of passing props down to children or connecting them
to the store are appropriate, however having nested connect()
components is actually going to give you more performance. The
downside is they're slightly more coupled to the application and
slightly harder to test, but that may not be a big issue.
He has also articulated a nice rule of thumb to follow on reddit
I do it this way:
Start by using one container and several presentational components
As presentational component tree grows, “middle” components start to pass too many props down
At this point, I wrap some leaf components into containers so that “middle” components don’t need to accept and pass down props that are
completely unrelated to them
Repeat
He has even tweeted regarding this:
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.
So in simple words:
You can use connect() at any level. Doing so makes the component smart, since it knows where its props come from. A dumb component just has props, and they could come from anywhere. A smart component is coupled to redux; a dumb component is not.
UPDATE: react-redux v7 and above
The same concept applies to useSelectors too. You can receive data in a container component and pass on to your presentational components, if multiple of its children make use of the same data
If however the data used by the children is different, you can choose to use useSelector individually within the child component. This will make sure that only those components re-render which actually need to
I would suggest if you are already using redux in your app then set the property in the redux store and fetch it in the component D.
But if the work flow is really simple and all the data is fetched from a single source per view, you can avoid redux as it is for complex state management.

Redux/MobX - Do I need to pass data in child components via props in React?

I know It may sound like a dumb question, But I am not able to get this solved in my head. Please bear with me.
In case when we use a state management system in React like Redux / Mob X, I guess the main purpose of these state management techniques is to provide a single source of Data and a more structured approach of updating it.
Say, I am Using a state management library(MobX) for React, And suppose I have a parent component which makes an http API call and updates the MobX store with the API response. Now I need that data in one of child/nested components.
My Question is, Should I pass that data as a prop to child component or should I enable child component to connect with Central Store and directly get that data ?
by connecting the child to store, I am turning the Child into a class component, which is making it more heavy and React optimisations may not apply. I am defeating the whole purpose of a functional component.
Awaiting replies.
Best Regards,
Lalit
This completely depends on the situation. I would suggest splitting your components up in 2 parts:
Components that could be re-used in other projects
(Higher level) Components that are so specific to this project that they probably never will be re-used.
For components of category 1, I would suggest not using mobx store directly, but instead make pure react components. (eg think of a dropdown, or an ajax dropdown component).
For second part components (think of, header, footer, section components specific for your website). just make them directly interact with the Mobx store, so that you can way quicker code what you need (instead of constantly having to prop everything).
addition
For components of category 1 you can always wrap them with the #inject() method. This way for example you could turn a dropdown component into a UserDropdown component that uses the mobx store for its state. (The inject method injects mobx state as props in the component).
const UserDropDownComponent = mobx.inject(stores => ({users: stores.userStore.users}))(DropDownComponent);
// usage:
<UserDropDownComponent />
Warning
For pure components wont always see changes of mobx state. To Fix this you need to wrap the component in an #observe annotation. Or you have to inject the props by wrapping it into: mobx.toJS(yourMobxStateProperty)

Use Connect or pass data as props to children

I am new to react and redux. I have a scenario where there are nested components like this.
A > B > C > D
There is a property used in A component and it will be used in D component. So, I have two approaches:
Get state from redux store in component A and then pass it along as props to all it's child components even though it will be used only in D component.
I should connect to redux store in component D and fetch that property from there.
What is the correct approach?
As Dan Abramov, author of redux says in this issue
Both approaches of passing props down to children or connecting them
to the store are appropriate, however having nested connect()
components is actually going to give you more performance. The
downside is they're slightly more coupled to the application and
slightly harder to test, but that may not be a big issue.
He has also articulated a nice rule of thumb to follow on reddit
I do it this way:
Start by using one container and several presentational components
As presentational component tree grows, “middle” components start to pass too many props down
At this point, I wrap some leaf components into containers so that “middle” components don’t need to accept and pass down props that are
completely unrelated to them
Repeat
He has even tweeted regarding this:
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.
So in simple words:
You can use connect() at any level. Doing so makes the component smart, since it knows where its props come from. A dumb component just has props, and they could come from anywhere. A smart component is coupled to redux; a dumb component is not.
UPDATE: react-redux v7 and above
The same concept applies to useSelectors too. You can receive data in a container component and pass on to your presentational components, if multiple of its children make use of the same data
If however the data used by the children is different, you can choose to use useSelector individually within the child component. This will make sure that only those components re-render which actually need to
I would suggest if you are already using redux in your app then set the property in the redux store and fetch it in the component D.
But if the work flow is really simple and all the data is fetched from a single source per view, you can avoid redux as it is for complex state management.

What to keep as presentational and container in Reactjs?

I am using React and Redux.
I have a question regarding what to keep as a Presentational and what to keep as container component
I have an App, which will have 3 sections
A carousel of banners
A collections for campaigns, each campaign will have products
A brand collection where each brand will have certain products
And products will have an action i.e. Add to Cart and same products can exist b/w Brands and Campaigns
3 API's are available one for each for getting data.
<App> ==> Presentational
<Banners/> ==> Container
<Campaigns/> ==> Container
<Brands/> ==> Container
</App>
Is my approach correct on this?
I think ultimately there is no "right" or "wrong" approach, it's simply a case of what works best for you.
If you are wanting to maintain a separation of container and presentational components, then as long as you stick to the principals you can compose your application in any way that makes sense.
E.g. I have presentational components that have container components composed within them - at some stage down the component tree there will be a purely presentational component that knows how stuff should look given its props and passes off event handlers to the container that controls it.
In the context of your app, this may look like:
<App> // Component provided it is simply composing other components and has no state etc
<BannersContainer/> // I assume that this is going to hook up to Redux actions and state with react-redux and may wrap a presentational <Banners/> component?
<CampaignsContainer/> // As above, except wrapping presentational <Campaigns/> component?
<BrandsContainer/> // As above except wrapping presentational <Brands/> component?
</App>
Then within your <Banners />, <Campaigns /> and <Brands /> presentational components, they too may compose themselves of both presentational and container components, depending on what levels of your component tree you may want to further hook into Redux state at.
I don't think that you should categorize in presentational/container groups based on content. Your question makes me think that you're splitting them based on what these components contain while you should be asking yourself what are they doing. I could easily find a presentational layer in every of these four components. For example the App may contain some layout grid markup which could be extracted or the banners for sure have some presentational markup because of the carousel.
My understanding for container is a component that knows where the data comes from and its structure so it can use it and pass whatever is needed down to the presentational component.
Often the presentational components have generic names like <GridColumn>, <NavHeader> or <CardTitle>. All these components above are really context specific so I would call them all container components.
You should keep components Presentational or Container as they end up to be. What I mean with this is that the context of the problem is more important than conventions.
In your case, let's take component and see how it will end up after connecting:
<App>
<Connect>
<Banners someProp={someDataFromStore}/>
<Banner> <Banner/>
<Banners/>
<Connect>
// ... other components
</App>
As you can see if you need someDataFromStore up in the component tree (App) or in other sibling components (Campaigns for example) you should connect it on a higher level, however, in some cases, it is better to connect them separately to avoid too much passing props down.
So the main point is to keep data flow as smooth as possible and to keep a single source of truth when it comes to data manipulations.

Is there a clean way to conditionally load and render different components for the same React Router route?

The use case is that I want to map the root (/) to one of two different components based on whether the user is logged in or not, and I want these two components to reside in different bundles and lazily loaded, so simply putting the login check in the render() method would not do.
I tried to use dynamic route definition with require.ensure() to lazily load the component, and it works for the first time, but after changing the login state the component doesn't get updated (even if I navigate to another route and back to / ).
I tried to force re-rendering the router by setting props on the component that contains the router, both manually and by making it a Redux connected component, and I also tried to add a listener to the Redux store and change the component state in response to login change, but in all of the attempts I got the error "You cannot change ; it will be ignored" and the component doesn't change.
My ugly solution is to have the different component loading code outside of the router, listen to the login state change and in response load the matching component and set it in the wrapping component's state, which is referenced in the render() code. Is there a clean "React-Router-ish" way to do what I want?
React Router 4 pretty much solves this as it made the route configuration part of the component rendering, so having conditional rendering is the same whether it's based on the location or on other props/state.
The closest thing to a clean "React-Router-ish" way to do that is to use the React Router Enterhooks.
An enter hook is a user-defined function that is called when a route is about to be rendered. It receives the next router state as its first argument. The replace function may be used to trigger a transition to a different URL.
So, use the onEnter(nextState, replace, callback?) attribute on your <Route />.
Called when a route is about to be entered. It provides the next router state and a function to redirect to another path. this will be the route instance that triggered the hook.
If callback is listed as a 3rd argument, this hook will run asynchronously, and the transition will block until callback is called.
The general best practice I follow is to place the auth-check flow away from your routes, and place it inside the transition events/hooks.
The usual behavior is - before the route handler actually gets rendered, check the auth, and redirect the user to another route. In your case, if you want to use the same route, but render different components - you should be able to do that using the same technique too. However, that's not a common thing (based on what I've seen), but it should be possible.
For a complete example of this approach, here's the auth-flow code example you can check. It is shared by the creators of React Router, so it looks credible to me.
PS: My answer is valid for React Router versions > 0.13.x.

Resources