如何将初始状态传递给减速器 [英] How to pass initial state to reducer

查看:56
本文介绍了如何将初始状态传递给减速器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前使用一个具有初始状态传递给我的reducer来创​​建我的商店.

I currently create my store with one reducer which has the initial state passed to it.

import reducers from './reducers'

const store = createStore(
    reducers,
    initialState,
    compose(...enhancers)
  )


// reducers.js
export default function reducer(state, action) {
  console.log('state', state)
  switch (action.type) {
    case 'LOAD_UI':
      return Object.assign({}, state, {
        loadUI: action.loaded
      });
    case 'NO_MATCH':
      return Object.assign({}, state, {
        loadUI: true,
        isNoMatch: action.isNoMatch
      });
    default:
      return state;
  }
}

当我在reducer函数中使用记录状态时,会得到配置商店时设置的状态:

When I log state with in my reducer function, I get the state that is set when I configure my store:

// if we are in production mode, we get the initial state from the window object, otherwise, when we are in dev env we get it from a static file
const preloadedState = window.__INITIAL_STATE__ === '{{__PRELOADEDSTATE__}}' ? initialState : window.__INITIAL_STATE__

const store = configureStore(preloadedState)

ReactDOM.render(
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>
, document.getElementById('root')
)

现在我要使用另一个减速器,因为我试图将Apollo包含在我的项目中.根据 http://dev.apollodata.com/react/redux.html 我需要合并Reducers:即

Now I want to use another reducer as I am trying to include Apollo in my project. According to http://dev.apollodata.com/react/redux.html I need to combineReducers: i.e.

combineReducers({
    todos: todoReducer,
    users: userReducer,
    apollo: client.reducer(),
  }),

所以我需要做这样的事情:

So I would need to do somthing like this:

const store = createStore(
    combineReducers({
      apollo: client.reducer(),
      reducer: reducers
    }),
    initialState,
    compose(...enhancers)
  )

但是然后我的化简函数不再有权访问状态(它是未定义的).我如何确保在使用CombineReducers时能够通过?

But then my reducer function no longer has access to state (it is undefined). How can I ensure this gets passed through when I use combineReducers?

解决方案:

根据丹尼尔·雷登(Daniel Rearden)的建议,我需要将减速器的钥匙与初始状态的钥匙匹配.

As per Daniel Rearden suggestion, I needed to match my reducers' keys to that of my initial state.

我的initialState看起来像:

My initialState looks something like:

{
  "pages": [
    {
      "id": 5,
      "title": "About",
      "slug": "about",
      "path": "/about",
      "template": "about",
      "published": "2017-07-10 02:02:30",
      "image": null,
      "seo": {
        "title": null,
        "description": null,
        "image": null,
        "fbAdmins": null,
        "gtm": null,
        "schema": ""
      },
      "sections": [
      ]
    },
    {
      "id": 10,
      "title": "Contact",
      "slug": "contact",
      "path": "/contact",
      "template": "contact",
      "published": "2017-07-11 04:27:30",
      "image": null,
      "seo": {
        "title": null,
        "description": null,
        "image": null,
        "fbAdmins": null,
        "gtm": null,
        "schema": ""
      },
      "sections": []
    },
    {
      "id": 4,
      "title": "Home",
      "slug": "home",
      "path": "/",
      "template": "home",
      "published": "2017-07-10 01:39:48",
      "image": null,
      "seo": {
        "title": null,
        "description": null,
        "image": null,
        "fbAdmins": null,
        "gtm": null,
        "schema": ""
      },
      "sections": []
    }
  ],
  "services": [],
  "clients": [],
  "people": [],
  "offices": [],
  "articles": [],
  "menus": {
    "header": [
      {
        "title": "Home",
        "slug": "/"
      },
      {
        "title": "About",
        "slug": "/about"
      },
      {
        "title": "Contact",
        "slug": "/contact"
      }
    ]
  },
  "settings": {
    "site": {
      "title": null,
      "siteUrl": ""
    },
    "logo": [],
    "secondarylogo": [],
    "favicon": [],
    "disclaimer": null,
    "tagline": null,
    "social": null,
    "email": null,
    "phone": null,
    "facebookAppId": "",
    "seo": {
      "title": null,
      "description": null,
      "image": null,
      "fbAdmins": null,
      "gtm": null,
      "schema": ""
    },
    "newsLetterSignUp": {
      "image": "",
      "title": "",
      "content": ""
    },
    "menu_settings": null
  }
}

所以我的减速器看起来像这样:

So my reducer looks something like this:

import { combineReducers } from 'redux'
import { ApolloClient } from 'react-apollo';

const client = new ApolloClient();

import articles from './articles'
import pages from './pages'
import services from './services'
import clients from './clients'
import people from './people'
import offices from './offices'
import menus from './menus'
import settings from './settings'

export default combineReducers({
  apollo: client.reducer(),
  articles,
  pages,
  services,
  clients,
  people,
  offices,
  menus,
  settings
})

因此,我的 pages reducer仅获取我的initialState的页面切片.

So that my pages reducer only gets the pages slice of my initialState.

推荐答案

之所以无法正常工作,是因为您已经更改了状态的结构以及传递给原始状态的内容减速器.您的商店在什么地方看起来像这样:

The reason this isn't working as you'd expect is because you've altered the structure of your state, as well as what gets passed to your original reducers. Where before your store looked something like this:

{
 loadUI: true
 isNoMatch: false
}

现在,您已经基本上告诉Redux寻找:

Now, you've basically told Redux to look for:

{
 apollo: {
   // ✁
 }
 reducers: {
   loadUI: true
   isNoMatch: false
 }
}

当您使用CombineReducers时,实际上是在为状态创建隔离域-而不是将整个状态传递给每个reducer,redux只会将状态的一部分传递给每个reducer,并且该reducer只能改变那片状态.通过如上所述构造商店,您已经告诉redux仅将状态的 apollo 片传递给apollo reducer ...和状态的 reducers 部分到原始的减速器.

When you use combineReducers, you are essentially creating isolated domains for your state -- instead of passing in the entire state to each reducer, redux will only pass in a slice of the state to each reducer and that reducer will only be able to alter that slice of state. By structuring your store as shown above, you've told redux to pass only the apollo slice of the state to the apollo reducer... and the reducers part of the state to your original reducers.

我猜您尚未对 preloadedState 进行任何更改.因此,发生的事情是redux在 preloadedState 中寻找一个称为 reducers 的属性,并将其传递给您的reducer.它找不到一个,因此它传递的是未定义的.

I'm guessing you haven't made any changes to preloadedState. So what's happening is redux is looking for a property in preloadedState called reducers and passing that to your reducers. It can't find one, so it passes in undefined.

这里最简单的解决方法是,首先选择比 reducers - ui 更具有描述性的内容?相应地更改您的CombineReducers.然后更新您的 preloadedState ,以使您拥有的任何初始状态都嵌套在 ui 中.然后它应该按预期工作.请记住,您还需要更新选择器和/或mapStateToProps函数!

The easiest fix here is, first, pick something more descriptive than reducers -- ui maybe? Change your combineReducers accordingly. Then update your preloadedState so that whatever intial state you had is nested inside ui. Then it should work as expected. Just keep in mind you'll need to update your selectors and/or mapStateToProps functions too!

:您可能想详细了解CombineReducers的工作方式

You may want to read up more about how combineReducers works here.

这篇关于如何将初始状态传递给减速器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆