92
votes

I normally post code related stuff on Stack, but this is more a question about what the general thoughts of the community are.

There seems to be a lot of people advocating the use Redux with React to manage data/state, but while reading and learning both I've come across something that doesn't quite look right.

Redux

At the bottom of this page: http://redux.js.org/docs/basics/UsageWithReact.html (Passing the Store) it recommends using the "Magic" of React 'Context'.

One option would be to pass it as a prop to every container component. However it gets tedious, as you have to wire store even through presentational components just because they happen to render a container deep in the component tree.

The option we recommend is to use a special React Redux component called to magically make the store available to all container components...

React

On the React Context page (https://facebook.github.io/react/docs/context.html) it has a warning at the top:

Context is an advanced and experimental feature. The API is likely to change in future releases.

Then at the bottom:

Just as global variables are best avoided when writing clear code, you should avoid using context in most cases...

Do not use context to pass your model data through components. Threading your data through the tree explicitly is much easier to understand...

So...

Redux recommends using the React 'Context' feature rather than passing the store along down to each component via 'props'. While React recommends the opposite.

Also, it seems that Dan Abramov (the creator of Redux) now works for Facebook (the creator of React), just to confuse me more.

  • Am I reading all this right..?
  • What is the general current consensus on this issue..?
3
Ahh this is a great question, I'm very curious to hear the viewpoints of others as well! I'm slightly afraid it'll get closed due to the discussion aspect. I really hope it doesn't.mejdev

3 Answers

93
votes

Context is an advanced feature and is subject to change. In some cases its conveniences outweigh its downsides so some libraries like React Redux and React Router choose to rely on it despite the experimental nature.

The important part here is the word libraries. If context changes its behavior, we as library authors will need to adjust. However, as long as the library doesn’t ask you to directly use the context API, you as the user shouldn’t have to worry about changes to it.

React Redux uses context internally but it doesn’t expose this fact in the public API. So you should feel much safer using context via React Redux than directly because if it changes, the burden of updating the code will be on React Redux and not you.

Ultimately React Redux still supports always passing store as a prop so if you want to completely avoid context, you have that choice. However I would say this is impractical.

TLDR: Avoid using context directly unless you really know what you are doing. Using a library that happens to rely on context internally is relatively safe.

5
votes

I don't know about others, but I prefer using react-redux's connect decorator to wrap my components so that only the props from the store I need are passed into my component. This justifies the use of context in a sense because I am not consuming it (and I know, as a rule, any code that I am in charge of will not consume it).

When I test my components, I test the non-wrapped component. Because react-redux only passed the props I needed on that component, I now know exactly what props I need when I'm writing the tests.

I suppose the point is, I don't ever see the word context in my code, I don't consume it, so to a certain degree, it doesn't affect me! This doesn't say anything about Facebook's "experimental" warning.. If context disappeared, I'd be just as screwed as everyone else until Redux was updated.

1
votes

There's an npm module that makes it really easy to add redux to the react context

https://github.com/jamrizzi/redux-context-provider

https://www.npmjs.com/package/redux-context-provider

import React, { Component } from 'react';
import ReduxContextProvider from 'redux-context-provider';
import createStore from './createStore';
import actions from './actions';
import Routes from './routes';

export default class App extends Component {
  render() {
    return (
      <ReduxContextProvider store={store} actions={actions}>
        <Routes />
      </ReduxContextProvider>
    );
  }
}