Redux,如果我想访问数据,是否必须在所有容器中导入 store? [英] Redux, Do I have to import store in all my containers if I want to have access to the data?

查看:36
本文介绍了Redux,如果我想访问数据,是否必须在所有容器中导入 store?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

也许我并没有把头放在 redux 上,但是我看到的所有示例都没有真正在容器之间访问太多状态,所以我没有看到 store.getState() 的太多用法,但即使你想派送,你需要访问商店,对吗?

所以,除了导入从路径/到/商店/商店"导入商店

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

解决方案

一般来说,您只想制作可以访问 store 的顶级容器组件 - 它们会将任何必要的数据或动作分派作为道具传递给他们的孩子组件.这是智能"和哑"组件之间的区别——智能"组件知道 Redux 存储/状态,而哑"组件只是将 props 传递给它们,而对更大的应用程序状态一无所知.

然而,即使只是将 store 传递给容器组件也会变得乏味.这就是 React-Redux 提供一个开箱即用的组件来包装整个应用程序的原因.在文档中查看.这是 Provider 组件,当你用它包装整个应用程序时,你只将 store 传递给组件一次:

import createStore from '../store';const store = createStore()类 App 扩展组件 {使成为() {返回 (<提供者商店={商店}><MainAppContainer/></提供者>)}}

正如你在这里看到的,我有一个单独的配置文件只用于我的商店,因为你可以做很多修改,对于任何远程复杂的应用程序,你会发现自己对使用 compose 来应用中间件.

然后您剩余的任何智能"组件(通常是包装器)都需要监听 store.这是使用 connect 方法完成的.这允许您将状态的各个部分映射到您的组件属性以及将操作作为属性进行调度.

import { bindActionCreators } from 'redux';从'react-redux'导入{连接};import * as actionCreators from './actionCreators';const mapStateToProps = 函数(状态){返回 {某物:state.something,}}const mapDispatchToProps = 函数(调度){返回 bindActionCreators({getSomething: actionCreators.getSomething,}, 派遣)}类 MainAppContainer 扩展组件 {componentDidMount() {//现在可以访问像this.props.something这样的数据,它来自商店//现在可以访问像 this.props.getSomething 这样的调度操作}使成为() {//将存储数据和分派动作传递给子组件返回 (<div><ChildComponent1 something={this.props.something}/><ChildComponent2 getSomething={this.props.getSomething}/>

)}}导出默认连接(mapStateToProps,mapDispatchToProps)(MainAppContainer)

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

基于上面的例子,你会看到因为我将 this.props.something 传递给 ChildComponent1,它可以访问 somethingcode> 来自商店的数据,但它无权访问 getSomething 调度操作.同样,ChildComponent2 只能访问 getSomething 调度操作,而不能访问 something 数据.这意味着您只将组件暴露给他们从商店需要的东西.

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

class ChildComponent2 扩展组件 {使成为() {返回 (<div><div onClick={this.props.getSomething}>点击我</div><NestedComponent getSomething={this.props.getSomething}/>

)}}

从评论中编辑

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

导出函数 getSomething() {返回 {类型:'GET_某事',有效载荷:{东西:'这是一些数据'}}}

此操作类型是您的减速器将侦听的内容,以了解正在触发哪个操作.

Perhaps I am not wrapping my head around redux, but all the examples I've seen don't really access state too much between containers and so I haven't seen much usage of store.getState(), but even if you want to dispatch, you need access to store, right?

So, other than importing import store from 'path/to/store/store'

in every file that I want to getState() or "dispatch", how do I get access to that state because if I don't include it, store is undefined.

解决方案

In general you want to only make top-level container components ones that have access to the store - they will pass down any necessary data or action dispatches as props to their children components. This is the difference between a "smart" and a "dumb" component - "smart" components know about the Redux store/state, while "dumb" components just get props passed to them and have no idea about the bigger application state.

However, even just passing the store to container components can become tedious. That's why React-Redux provides one component out of the box that wraps your entire application. Check it out in the docs. This is the Provider component and when you wrap your whole app with it, you only pass the store to a component once:

import createStore from '../store';

const store = createStore()

class App extends Component {

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

As you can see here, I have a separate configuration file just for my store as there is a lot of modification you can do and for any remotely complex app, you'll find yourself doing the same for things like using compose to apply middleware.

Then any of your remaining "smart" components (generally wrappers) need to listen to the store. This is accomplished using the connect method. This allows you to map pieces of the state to your component properties as well as dispatch actions as properties.

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)

Because you are always passing down dispatch actions and data to your children component as properties, you just reference those on that component with this.props.

Building off the example above, you'll see that because I passed this.props.something to ChildComponent1, it has access to the something data from the store but it does not have access to the getSomething dispatch action. Likewise, ChildComponent2 only has access to the getSomething dispatch action but not the something data. This means that you only expose components to exactly what they need from the store.

For example, because ChildComponent2 was passed down the dispatch action as getSomething, in my onClick I can call this.props.getSomething and it will call the dispatch action without needing any access to the store. In the same way it can continue to pass down getSomething to another child component and that component could call it and/or pass it down and the cycle could continue indefinitely.

class ChildComponent2 extends Component {

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

Edit from the comments

While this doesn't pertain directly to the question, in the comments you seemed a little confused about actions. I did not actually define the action getSomething here. Instead it is usual in Redux apps to put all of your action definitions in a separate file called actionCreators.js. This contains functions that are named the same as your actions and return an object with a type property and any other methods/data that action requires. For instance, here's a very simple example actionCreators.js file:

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

This action type is what your reducer would listen for to know which action was being fired.

这篇关于Redux,如果我想访问数据,是否必须在所有容器中导入 store?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆