如何将初始状态传递给减速器

IT技术 reactjs redux graphql
2021-04-29 01:15:00

我目前使用一个减速器创建我的商店,该减速器将初始状态传递给它。

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 函数中记录状态时,我会得到在我配置我的商店时设置的状态:

// 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:即

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

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

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

但是后来我的减速器函数不再可以访问状态(它是未定义的)。当我使用 combineReducers 时,如何确保它通过?

解决方案:

根据 Daniel Rearden 的建议,我需要将我的减速器的键与我的初始状态的键相匹配。

我的初始状态看起来像:

{
  "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
  }
}

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

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减速器就只能获取我的初始状态的页面切片。

1个回答

这不像您期望的那样工作的原因是因为您改变了状态的结构,以及传递给原始减速器的内容。以前您的商店看起来像这样:

{
 loadUI: true
 isNoMatch: false
}

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

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

当您使用 combineReducers 时,您实际上是在为您的状态创建隔离域——而不是将整个状态传递给每个减速器,redux 只会将状态的一部分传递给每个减速器,并且该减速器只能改变它状态片。通过如上所示构建您的商店,您已经告诉 redux 只apollo将状态切片传递给 apollo 减速器……并将reducers状态一部分传递给原始减速器。

我猜你没有对preloadedState. 所以发生的事情是 redux 正在寻找一个preloadedState被调用的属性reducers并将它传递给你的减速器。它找不到一个,所以它传入了 undefined。

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

编辑:您可能想在此处阅读有关 combineReducers 如何工作的更多信息