Does the React Context API replace the need for component props? - javascript

I've recently upgraded a React 15 project to use React 16.9. Specifically, I've completely replaced redux with the new Context API, pure functional components, and hooks. With the Context API, we also gain the ability for nested child consumers to obtain the data without having to pass it using props all the way through. However, I noticed that I don't have any component props anywhere as everything is passed via provider/consumer context.
So my question is does the context API make component props obselete?

I find people abuse redux and context. Btw, redux uses context internally.
To be honest, prop still should be your best friend in most of cases. Only when you want to avoid nested prop passing, you could then explore context where a provider is created as a parent, and then all deep down children can receive it as props.
Prop is still the way when children connect to the provider. The only difference is that these props are stored in a sort of "global" space now.
So in short, context doesn't replace prop, it still uses prop.

You have already answered your question. Context API avoids I quote one from react docs :
Context is primarily used when some data needs to be accessible by many components at different nesting levels. Apply it sparingly because it makes component reuse more difficult
There is no other reason. If I want to reuse component or export it that depends context, user has no idea about it. Use cases like logged User, theme, or sone global state like work flow detail for the whole application etc, makes a good use case.

Related

What is a good practice to access the parent component's ref inside its child?

I'm coding a small library with a simple structure: one parent component can contain multiple components of the same type as direct children. Here is a sample schematic diagram for the app:
By current design, a ChildComponent must address a variety of properties of their parent MainComponent, and I am looking for a good practice that can help achieve that or an alternative of an app structure that will lead to a good practice.
My considerations:
Using Context API. This won't go well with the goal in mind because of the nature of contexts. As per linked documentation:
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.
Passing all required props from MainComponent to ChildComponent. Despite I meet this approach quite often, I don't think it is good because it leads to duplicate code.
The simplest way is with Props, as you already mentioned. If you are passing only one level down it is probably the best option:
https://reactjs.org/docs/components-and-props.html
If you need to pass code to several children and grandchildren, using props will get annoying, that is called "propdrilling". You can avoid it using a Context that will provide to all the components that want to consume it:
https://reactjs.org/docs/context.html
Another alternative for larger applications is Redux. Is has a store and enables your components to interact with the Redux store. The downside is that it requires a lot of boilerplate.
https://react-redux.js.org/

Connecting child components to store vs connecting parent component to store and passing down props

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

React Context API & HOC

I've been reading up on the new context API and have a question regarding using it alongside HOC to inject props instead of directly wrapping every child that needs access to some state with a Consumer.
Isn't the above achievable without context? Isn't it possible to just house some state in a HOC and inject that into wrapped components that need access?
It is possible but each wrapped component will have it's own data passed from HOC. While using context, this data is shared between components.
So changing data in a context will make all Consumers re-render, while HOC will work only for the wrapped component.
The documentation explains the use case where a lot of components need to access the common theme, and hence can be wrapped with an HOC. without the context, you can make use of HOCs state to store the variable and pass on to the components wrapped with HOC but all of these components will have a different instance of the state and won't react to the theme change together.
Context makes it possible to store the data centrally and all listeners/consumers will react to the change together.

why do I need redux in react native?

I am trying to find out why do I need redux if RN already have state, I can use state as I want as action or change something.
So why would I need it?
Redux provides a "shared state" that every component can access. For example, you may have found that a parent component needs to be aware of the state of a child component. You can resolve this in React alone by passing down a method as props to the child but this isn't a pattern you want to be repeating again and again, especially as your component structure becomes more complex and hierarchical. Redux provides an elegant solution. For small apps though, it's probably not necessary.

How to handle global state data into deeply nested components in Redux?

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.

Categories