Redux,如果我想访问数据,是否必须在所有容器中导入存储?

Redux, Do I have to import store in all my containers if I want to have access to the data?

也许我并没有全神贯注于 redux,但我看到的所有示例并没有真正在容器之间访问太多状态,所以我没有看到 store.getState() 的太多用法, 但即使你想发货,你也需要访问商店,对吗?

所以,除了导入 从 'path/to/store/store'

导入商店

在我想要 getState() 或 "dispatch" 的每个文件中,我如何才能访问该状态,因为如果我不包含它,存储是未定义的。

如果您使用 react-redux 包,您将最终用 store 道具将组件包装在 Provider 中。这将在 React 上下文中设置您的单个商店,然后从子组件中的 connect 方法访问它。 connect 方法采用两个函数(mapStateToProps 和 mapDispatchToProps),它们是您从商店获取状态和发送消息的挂钩。

Take a look here for more information

一般来说,您只想制作可以访问商店的顶级容器组件——它们会将任何必要的数据或动作分派作为道具传递给它们的子组件。这是 "smart" 和 "dumb" 组件之间的区别 - "smart" 组件了解 Redux store/state,而 "dumb" 组件只是将道具传递给它们并且不知道更大的应用程序状态。

然而,即使只是将存储传递给容器组件也会变得乏味。这就是 React-Redux 提供一个开箱即用的组件来包装整个应用程序的原因。 Check it out 在文档中。这是 Provider 组件,当你用它包装整个应用程序时,你只将商店传递给组件 once:

import createStore from '../store';

const store = createStore()

class App extends Component {

  render() {
    return (
      <Provider store={store}>
        <MainAppContainer />
      </Provider>
    )
  }
}

正如您在此处看到的,我有一个单独的配置文件,仅适用于我的商店,因为您可以进行大量修改,对于任何远程复杂的应用程序,您会发现自己对诸如使用compose 应用中间件。

然后您剩余的任何 "smart" 组件(通常是包装器)都需要监听存储。这是使用 connect 方法完成的。这允许您将状态片段映射到您的组件属性以及将操作作为属性分派。

import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as actionCreators from './actionCreators';

const mapStateToProps = function(state){
  return {
    something: state.something,
  }
}

const mapDispatchToProps = function (dispatch) {
  return bindActionCreators({
    getSomething: actionCreators.getSomething,
  }, dispatch)
}

class MainAppContainer extends Component {

    componentDidMount() {
      //now has access to data like this.props.something, which is from store
      //now has access to dispatch actions like this.props.getSomething
    }

    render() {
        //will pass down store data and dispatch actions to child components
        return (
               <div>
                   <ChildComponent1 something={this.props.something} />
                   <ChildComponent2 getSomething={this.props.getSomething} />
               </div>
        )
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(MainAppContainer)

因为您总是将调度操作和数据作为属性传递给您的子组件,所以您只需使用 this.props.

引用该组件上的那些

基于上面的示例,您会看到因为我将 this.props.something 传递给 ChildComponent1,它可以访问商店中的 something 数据,但它没有访问 getSomething 调度操作。同样,ChildComponent2 只能访问 getSomething 调度操作,但不能访问 something 数据。这意味着您只将组件公开给他们从商店中需要的东西。

例如,因为 ChildComponent2 作为 getSomething 传递给调度操作,在我的 onClick 中我可以调用 this.props.getSomething 并且它将调用调度操作 无需访问商店。以同样的方式它可以继续向下传递 getSomething 到另一个子组件并且该组件可以调用它 and/or 向下传递它并且循环可以无限期地继续。

class ChildComponent2 extends Component {

    render() {
        return (
            <div>
                <div onClick={this.props.getSomething}>Click me</div>
                <NestedComponent getSomething={this.props.getSomething} />
            </div>
        )
    }
}

根据评论编辑

虽然这与问题没有直接关系,但在评论中您似乎对操作有些困惑。我实际上并没有在这里定义动作 getSomething 。相反,在 Redux 应用程序中通常将所有操作定义放在一个名为 actionCreators.js 的单独文件中。这包含与您的操作同名的函数和 return 具有 type 属性 和操作所需的任何其他 methods/data 的对象。例如,这是一个非常简单的示例 actionCreators.js 文件:

export function getSomething() {
    return {
        type: 'GET_SOMETHING',
        payload: {
            something: 'Here is some data'
        }
    }
}

这个动作类型是你的 reducer 会监听的类型,以了解触​​发了哪个动作。

使用 mapStateToProps 反应组件:

import Item from './Item.jsx';
import { createStore } from 'redux';
import { getProduct, addProduct } from '../../actions';
import { connect } from "react-redux";

class Bundles extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    var productData = this.props.productData
    return (
      <div>
        <span>
          {
            productData.map(item => (
              <Item item={item} key={item.id} />
            ))
          }

        </span>
      </div >
    )
  }
}

const mapStateToProps = (state) => {
  // console.log(state.getProduct)
  return {
    productData: state.getProduct,
  };
};

export default connect(mapStateToProps)(Bundles);

产品减速器


const productReducer = (state = data, action) => {
  switch (action.type) {
    case "GET_PRODUCT":
      console.log(state)
      return state
    default:
      return state;
  }
}

export default productReducer;

RootReducer(所有减速器合并)

import getProduct from './products';
import getReviews from './reviews';

import { combineReducers } from 'redux';

const allReducers = combineReducers({
  cartReducer, getProduct, getReviews
})

export default allReducers;

动作 (action/index.js)

      // console.log('hahahahah')
      return {
        type: 'ADD_PRODUCT',
        payload: n
      }
    }