So say you have a chat aplication with this component structure:
<ChatApp>
<CurrentUserInfo>...</CurrentUserInfo>
<ChatsPanel>...</ChatsPanel>
<SelectedChatPanel>
<MessagesList>
<MessageBaloon>
<MessageText></MessageText>
<MessageUserHead></MessageUserHead>
</MessageBaloon>
...
</MessagesList>
<SelectedChatPanel>
</ChatApp>
And a Redux state like:
{
currentUser: ...,
chatsList: ...,
selectedChatIndex: ...,
messagesList: [ ... ]
}
How would you make the current user information available to the <MessageUserHead> component (that will render the current user thumbnail for each message) without having to pass it along all the way from the root component thru all the intermediate components?
In the same way, how would you make information like current language, theme, etc available to every presentational/dumb component in the component tree without resorting to exposing the whole state object?
(UPDATE: Having spent some time on option 4, I personally think it's the way to go. I published a library, react-redux-controller built around this approach.)
There are a few approaches that I know of from getting data from your root component, down to your leaf components, through the branches in the middle.
Props chain
The Redux docs, in the context of using react-redux, suggest passing the data down the whole chain of branches via props. I don't favor this idea, because it couples all the intermediate branch components to whatever today's app structure is. On the bright side, your React code would be fairly pure, and only coupled to Redux itself at the top level.
Selectors in all components
Alternatively, you could use connect to make data from your Redux store available, irrespective of where you are in the component tree. This decouples your components from one another, but it couples everything to Redux. I would note that the principle author of Redux is not necessarily opposed to this approach. And it's probably more performant, as it prevents re-renders of intermediary components due to changes in props they don't actually care about.
React children
I haven't thought a great deal about doing things this way, but you could describe your whole app structure at the highest level as nested components, passing in props directly to remote descendants, and using children to render injected components at the branch levels. However, taken to the extreme, this would make your container component really complicated, especially for intermediate components that have children of more than one type. Not sure if this is really viable at all for that reason.
React context
As first mentioned by #mattclemens, you can use the experimental context api to decouple your intermediate components. Yes, it's "experimental". Yes, the React team definitely doesn't seem to be in love with it. But keep in mind that this is exactly what Redux's connect uses to inject dispatch and props from selectors.
I think it strikes a nice balance. Components remain decoupled, because branch components don't need to care about the descendants' dependencies. If you only use connect at the root to set up the context, then all the descendents only need to couple to React's context API, rather than Redux. Components can freely be rearranged, as long as some ancestor is setting the required context properties. If the only component that sets context is the root component, this is trivially true.
The React team compares using context to global variables, but that feel like an exaggeration. It seems a lot more like dependency injection to me.
For information that is global to all of your "dumb" components, you could use react contexts.
A contrived example
// redux aware component
var ChatApp = React.createClass({
childContextTypes: {
language: React.PropTypes.string
},
getChildContext: function() {
// or pull from your state tree
return {language: "en"};
},
...
}
// dumb components
var ExDumb = React.createClass({
contextTypes: {
language: React.PropTypes.string
},
render: function() {
var lang = this.context.language;
return ( <div /> );
}
});
In response to the comments, redux uses this context approach in their react-redux library.
And more abstractly for use outside of react, you could use some sort of pluck or selector function on the state tree, and return only a subset of the global state needed by dumb components.
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
I noticed new feature portals do the same thing but better? I dont know much about portals but it seems to be the new way to manage nested component updates?
I knew Reacts Context API was experimental, and noticed componentDidUpdate no longer receives prevContext and they dropped contextTypes.
I also noticed they are introducing React 16's Portal API and not sure if this is intended to replace the Context API.
So again, as mentioned above, is React 16's Portal API meant to replace the Context API?
EDIT: To piggyback on this topic, is conext the best way to manage i18n localization in react?
TL;DR => Portals and Context solve different purposes, one is to inject DOM at any level and other is to inject props at any level. Context can mimic Portals but Portals AS OF NOW cannot mimic Context not at least without introducing code smell.
NOTE: Below is based on my understanding of the two concepts, if anyone has further thoughts or corrections on this please feel free to edit the answer.
From what I was able to understand Portals are, as the name suggests, a door way for you to render components that need not be in the component tree hierarchy. This works like perfectly for Modals, Popovers or any component which needs to be stitched at a particular location in the tree.
Context is to communicate with various sibling and child components without having to pass props all the way down from parent to the intended component. Of course, this is an important feature to have but it remained in the experimental phase probably due to the fact that this can be achieved by event-emitters and Redux, MobX for a centralized state management.
I am assuming that your use case for i18n would require a lot of communication across components for which you might want to look at this great article
COMPONENT COMMUNICATION
Portals and Context help achieving this kind of communication but there is a difference. Portals can render or inject DOM at any level and Context can inject props at any level in the subcomponent tree.
You can always achieve what Portals are able to do using Context but I don't think Portals can mimic Context functionality.
EG: Something like this can be done to mimic what Portals do using Context. Where as in Portals AFAIK you can only send DOM Nodes ReactDOM.createPortal(child, container). May be there is a way to achieve the functionality but that would surely lead to code smell.
class Parent extends React.Component {
getChildContext() {
return {
renderModal: this.renderModal
}
}
renderModal = (children) => {
this.setState({
open: !this.state.open,
injectableChildren: children
})
}
render() {
this.state.open
?
<div>
{this.state.injectableChildren}
</div>
:
null
// JSX
}
}
class SomeSibling extends React.Component {
static contextTypes = {
renderModal: React.PropTypes.func
}
handleOnClick = (event) => {
this.context.renderModal(renderableChildJSX);
}
renderableChildJSX = () => (
<div>
YAY I AM GETTING RENDERED AT THE ROOT
</div>
)
render() {
return(
<div onClick={this.handleOnClick}>
</div>
)
}
}
In my case, I feared from using Context despite it's flexibility due to the fact that React docs always mentioned that it's an experimental feature and warned repeatedly from using this feature full-blown. My guess is that React is looking at stabilising this feature or completely scrape it off the React codebase which is a risk that could go both ways.
CONCLUSION: IMO, Portals in it's current state and the problem it is trying to resolve is entirely different from what Context is built for and it is better to use event-emitters with the only reason that Context might possibly be deprecated.
A Portal API is different from a Context API,
Portals provide a first-class way to render children into a DOM node
that exists outside the DOM hierarchy of the parent component.
A portal is useful when you might want to render Modals or Popovers, that need to be outside of the current DOM hierarchy in order for it to have proper z-indexes. Most often you would render these in the top level directly. However with Portal you can render DOM element at any level of hierarchy.
In React 16, portals can be created like
ReactDOM.createPortal(child, container)
Context on the other hand is used to pass the data onto different component without the need to pass if down at each level. You may have components at different level, some of which may be extremely nested and passing the props down all the way at each level might not be a great solution and it comes with significant performance hindrance, since a lot the higher levels may not actually be using these props but will still re-render on such prop changes.
From v16.3.0 React has introduced a new context API and context is no longer experimental.
Context is designed to share data that can be considered “global” for
a tree of React components, such as the current authenticated user,
theme, or preferred language. Using context, we can avoid passing
props through intermediate elements. but it shouldn't be used to just
pass props a few levels down
In general you would use context like
export const MyContext = React.createContext();
class Provider extends React.Component {
state = {
theme: 'dark'
}
handleChange=() => {}
render() {
return <MyContext.Provider
value={{state: this.state, handleChange: this.handleChange}}
>
{this.props.children}
</MyContext.Provider?>
}
}
and for the Component you want to use context value, you would write
import {MyContext} from 'path/to/context'
...
render() {
return <MyContext.Consumer>
{(theme) => <div>{theme}</div>}
</MyContext.Consumer>
}
To piggyback on this topic, is context the best way to manage i18n
localisation in react?
Yes i18n localisation is a good usecase for using context since you would need to pass on language/paramerisation selection throughout your app. In cases where you need much more integration with APIs to do localisation, you can think about using Redux.
For more details check this answer on whether to use Context or Redux
I'm fairly new to React and I'm trying to understand a clean way for child components to communicate with each other.
In a simple component, I know that I can make use of props to pass data to child and callbacks for children to pass data back to parent component.
In a slightly more complex case, when I have multiple children components in a parent component, the communication between the children gets a little confusing. I'm not sure what I should do for children components of the same level to communicate with each other.
In my case, I decided that, maybe, I could use states. So I will have a state value in the parent component, and pass it on the children's props. Similarly, the callback handlers (called from the children component) in the parent component will help to set the states accordingly so that a state value gets passed on from one child to another through React's binding.
And a pseudo code could look something like:
//Inside Parent Component
constructor() {
//initialise state for the child components
this.setState({testList: []});
}
render() {
return (
<div>
<ChildA onSomething={this.onSomethingHandler} testList={this.state.testList} />
<ChildB onSomethingElse={this.onSomethingElseHandler} testList={this.state.testList} />
</div>
);
}
onSomethingHandler(evt):void {
if(blah.blah.blah) this.setState({testList: this.state.testList.splice().push(evt.value)};
}
onSomethingElseHandler(evt):void {
//Some other complex biz logic...
if(blah.blah.blah) this.setState({testList: this.state.testList.splice().push(somethingOtherStuffDueToLogic)};
}
//Inside ChildA Component
export IChildAProps {
onSomething: (evt)=>void
}
render() {
//Do some logic from the value in testList property
if(this.state.testList == blah blah)...
return (
<button onClick={this.props.onSomething({id:321, value:"wassup! I'm ChildA."})}>ChildA</button>
)
}
//Inside ChildB Component
export IChildBProps {
onSomethingElse: (evt)=>void
}
render() {
//Do some logic from the value in testList property
if(this.state.testList == blah blah)...
return (
<button onClick={this.props.onSomething({id:123, value:"yo! I'm ChildB."})}>ChildB</button>
)
}
At this point, I'm starting to wonder if the logic in that 2 handler methods, namely onSomethingHandler() and onSomethingElseHandler() in the Parent component, should actually be resided inside the child components themselves? I thought of this because those logic look like something the child component should be handling on their own to serve their purpose. The parent component shouldn't do it for them or it might just grow messy. But I've no choice because of how I'm handling their communication. Apart from this, I also created a new state simply just to allow them to communicate.
So far, this is still relatively manageable. But in my own experiment, it has got to a stage where I've children component nested inside another children components that need to communicate across other children components of the same (or sometimes different) level. Using states for communication also meant that I have many states all over the place, which doesn't look like a good idea to me. And the parent components ended up with tons of messy callback handler methods to manage all that propagation of data up and down the component tree.
The situation is so messy that I can at most illustrate it as something like so:
And you can see in the above illustration, ChildB ended up having yet another state just to help passing that information between its children components.
I'm sure I'm missing something that I should know about React. The callbacks I'm having in the parent components seem a little too much just to handle data propagation. How should I really organise the communication of children components in a clean and maintainable way?
Every React programmer hits this wall at some point in time. I did too. The answer is to use Redux for state management. You have experienced how tedious it is to use React's native state.
Redux is a state management mechanism which can be used in conjunction with React. So you won't be using React's state, instead you will use Redux.
Redux provides a single store, where the state of entire application is stored. You can access the state in your components using connect() method.
But there is a caveat. Not all of the react components are connected to the Redux store. There are two types of components-
Smart/connected components: Connected to redux store
Dumb components: Dependent on connected components
The idea is to pass the state from redux store to Connected components via React's props. The connected components can directly consume state from the store. The dumb components are not directly connected to the redux store. The connected components also pass the state to the dumb components via props. So you see, React's state is bypassed altogether. Now, if you want to change the state, following events must happen-
An event is fired from the smart/dumb component.
Actions are dispatched to the store
Reducers create a new state according to the actions.
A new state will be stored in the store.
Store will return new state to the connected components via connect() through props
Dumb components will receive new state from connected components through props
What are actions and reducers?
Actions are nothing but javascript objects that describe how to change the state.
Reducer is a "pure" function which builds and returns the new state tree according to the action dispatched to the store.
Redux - http://redux.js.org/
Redux-thunk - https://github.com/gaearon/redux-thunk
Redux-saga - https://github.com/yelouafi/redux-saga
Most fashion way is using Redux.js (or flux.js) to matain your child components state.
http://redux.js.org/
If you don't like invoke third party js. You can use refs property:
https://facebook.github.io/react/docs/more-about-refs.html
We can use the react context API,
Context provides a way to pass data through the component tree without having to pass props down manually at every level
Also, note that Mark Erikson has mentioned in his blog,
Yes, the new context API is going to be great for passing down data to deeply nested components - that's exactly what it was designed for.
If you're only using Redux to avoid passing down props, context could replace Redux - but then you probably didn't need Redux in the first place.
Context also doesn't give you anything like the Redux DevTools, the ability to trace your state updates, middleware to add centralized application logic, and other powerful capabilities that Redux enables.
To handle scenarios you mentioned, context API is a good option and you don't have to use additional libraries for that.
I am a bit confused by the statements: "Renders the whole application" and "Passing state to child components".
Example 1:
I have a todos app with a AppComponent and TodosListComponent. The AppComponent grabs the array of todos from the store and passes it as a property to the TodosListComponent.
Example 2:
I have a huge application with lots state. I have like 50 components building up my app. Do I want to pass all the state from the stores from AppComponent down through all the 50 components?
So I am wondering, what is the convention? It makes more sense to me to let individual components listen directly to the stores they care about. The advantage is that only individual components rerender, but why then the concept of "the whole application rerender on state change"?
What are the pros and cons of each? What is the common convention?
There are a few ways you can handle this. I think they're all valid and have their own trade-offs.
Get all the state and pass pieces of it to children
This is the technique you specifically asked about. Using this method, you'll have some function or method available to your top-level component that turns all the data from the stores into a "big bag of state" and then you'll selectively pass pieces of this data to child components. If those components have their own children, they'll pass it along as necessary.
The upside to this method is that it makes things generally easy to debug. If you have to change the way a piece of state is retrieved from a store, you only have to change it in the top-level component—as long as it gets passed down with the same name, the other components will "just work." If some piece of data is wrong, you should only need to look in one place to figure out why.
The downside to this technique what I call "props explosion"—you can end up passing a lot of properties around. I use this method in a medium-sized flux application, and a snippet of the top-level application component looks like this:
<section id="col-left">
<Filters loading={this.state.loading}
events={this.state.events}
playbackRate={this.state.videoPlayback.playbackRate}
autoPlayAudio={this.state.audioPlayback.autoPlay}
role={this.state.role} />
</section>
<section id="col-center" className={leftPaneActive ? "" : "inactive"}>
<SessionVideo videoUuid={this.state.session.recording_uuid}
lowQualityVideo={this.state.session.low_quality_video_exists}
playbackRate={this.state.videoPlayback.playbackRate} />
<section id="transcript">
<Transcript loading={this.state.loading}
events={this.state.events}
currentEvents={this.state.currentEvents}
selection={this.state.selection}
users={this.state.session.enrolled_users}
confirmedHcs={this.state.ui.confirmedHcs}
currentTime={this.state.videoPlayback.position}
playing={this.state.videoPlayback.playing} />
</section>
</section>
In particular, there can be a lot of components between the top-level one and some eventual child that do nothing with the data except pass it along, more closely coupling those components to their position in the hierarchy.
Overall, I like the debuggability this technique provides, though as the application grew larger and more complex I found it was not idea to do this with only a single top-level component.
Get all the state and pass it as one object
One of the developers at Facebook mentioned this technique. Here, you'll get a big bag of state, just as above, but you'll pass the whole thing (or entire sub-sections of it) rather than individual properties. By utilizing React.PropTypes.shape in child components, you can ensure that the right properties are getting passed.
The upside is you pass way fewer properties around; the above example might look more like this:
<section id="col-left">
<Filters state={this.state} />
</section>
<section id="col-center" className={leftPaneActive ? "" : "inactive"}>
<SessionVideo session={this.state.session}
playback={this.state.videoPlayback} />
<section id="transcript">
<Transcript state={this.state} />
</section>
</section>
The downside is that it becomes a little more difficult to deal with changes in the shape of the state; rather than just changing the top-level component, you'll have to track down everywhere that piece of data is used and change the way that component access the property. Also, shouldComponentUpdate can potentially become a little trickier to implement.
Allow components to get their own state
On the other end of the spectrum, you can grant application-specific (that is, non-reusable) child components to access the stores and build up their own state based on the store change events. Components that build their own state like this are sometimes called "controller-views" or, more commonly these days, "container components."
The upside, of course, is that you don't have to deal with passing properties around at all (other than change handlers and properties for more reusable components).
The downside, though, is that your components are more highly coupled to the stores—changing the stores or the data they provide (or the interface via which they provide that data) may force you to revisit the code for a larger number of components.
Also, as mentioned in the comments, this can potentially make server rendering a bit more difficult. If you only use properties (especially at only the top level), you can transport them more easily to the client and re-initialize React with the same properties. By allowing the stores to determine their own data, you need to somehow inject that data into the stores to allow the components to get that data.
A common approach, and one that I typically use now, is to make every component in your application only rely on props for global application state, and then decide if it makes more sense to (1) connect them directly to flux by wrapping them in a container, or (2) allow the props to be passed from some parent container.
There are abstractions that you might be able to use to make some of these techniques more viable. For example, a Facebook dev had this to say in a comment on Hacker News:
Now all your data is in stores, but how do you get it into the specific component that needs it? We started with large top level components which pull all the data needed for their children, and pass it down through props. This leads to a lot of cruft and irrelevant code in the intermediate components. What we settled on, for the most part, is components declaring and fetching the data they need themselves, except for some small, more generic components. Since most of our data is fetched asynchronously and cached, we've created mixins that make it easy to declare which data your component needs, and hook the fetching and listening for updates into the lifecycle methods (componentWillMount, etc).
Jason Bonta from Facebook explained the concept of "Containers" in his React.js Conf 2015 talk.
To summarize: containers are simply components that wrap other components, and take care of any data-related concerns such as talking to stores, while the underlying component is focused solely on the view (markup/styles/etc.) and doesn't care where the data comes from.
This makes the component
highly re-usable because it can be wrapped with a different container when data needs to come from a different place,
not contain irrelevant state, therefore easier to implement and optimize shouldComponentUpdate, and
using composition rather than mixins for this aligns with what is likely the future of React with ES6, which does not have idiomatic mixins.
UPDATE March 2019: Look into React Hooks. With hooks, you can accomplish the same goal as described above, but abstract data-related concerns, such as talking to stores, in re-usable chunks of code that can be applied to multiple components. The ReactConf talk React Today and Tomorrow and 90% Cleaner React With Hooks by Dan Abramov does a great job of explaining hooks, and how they are different from both mixins and past composition approaches.