Redux with React - right way to share the store wi

2019-07-15 03:59发布

问题:

The store service from Redux is what ultimately utilized by various components in a React App. The methods (such as dispatch, getState and subscribe) exposed by it are used by all kinds components (like container or presentational).

I think the approach to pass this store service around is an important design decision. I see two approaches and they are:

1) By passing the store as a prop to every component at all nested levels. This is not the recommended one.

2) Use a tool like react-redux, which with the help of context, makes the store (state and dispatch to be exact) available wherever it is needed.

My questions are: Why not simply import the store wherever it is needed. For an SPA-based React App, store will be a singleton. Components nested at any level can simply import the store. Why should we adopt anyone of the above two approaches?

For a component at any nested level: Can we do this

import store from  "path/to/store";

let MyComponent = () => {
    let state = store.getState();

    return (
        <div onClick={() => {
            store.dispatch({
                type: "SOME_EVENT",
                payload: store.somedata
            });
        }}>{state.dataINeedHere}</div>
    );
};

export default MyComponent;

instead of

import { connect } from "react-redux";

let MyComponent = ({somedata, onMyAction}) => {
    let state = store.getState();

    return (
        <div onClick={() => {
            onMyAction(somedata);
        }}>{somedata}</div>
    );
};

const mapStateToProps = (state) => {
  return {
    somedata: state.somedata
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onMyAction: (input) => {
      dispatch({
          type: "SOME_EVENT",
          payload: input
      });
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);

回答1:

The Redux FAQ covers this question, at http://redux.js.org/docs/FAQ.html#store-setup-multiple-stores.

Summarizing: while you can directly import a store, you're tying your code to that store implementation, which makes it less reusable and harder to test. Ideally, none of your own code actually ever references the store directly. Connected components, middleware, and thunked action creators all receive the relevant dispatch and getState function references by dependency injection, making them reusable and allowing easy mocking of behavior for testing.



回答2:

Consider what happens when you have a second MyComponent, which manages data from a different part of the store. Your options are to tell each exactly how to access/update its data:

<Container>
   <MyComponent path="/a/b/c" />
   <MyComponent path="/a/b/d" />
</Container>

or you can give each access to only what it needs:

<Container>
   <!-- context /a/b was passed to Container -->
   <MyComponent data={c} onUpdate={update(c)} />
   <MyComponent data={d} onUpdate={update(d)} />
</Container>

The latter makes the MyComponent much simpler and much more flexible.