【问题标题】:Redux: Unexpected key found in preloadedState argument passed to createStoreRedux:在传递给 createStore 的 preloadedState 参数中找到意外的键
【发布时间】:2017-02-24 11:25:19
【问题描述】:

你能帮我解决异常吗Unexpected key "userName" found in preloadedState argument passed to createStore. Expected to find one of the known reducer keys instead: "default". Unexpected keys will be ignored.

我发现了这个Link,但它对我没有帮助。我不明白什么,也许这部分来自文档:与传递给它的键具有相同形状的普通对象

你能解释一下我在示例中的错误吗?

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from 'react-redux';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import  App from './containers/App.jsx';
import * as reducers from './reducers'
import types from './constants/actions';

const reducer = combineReducers(reducers);

const destination = document.querySelector("#container");

var store = createStore(reducer, {
    userName : ''
});


ReactDOM.render(
    <Provider store={store}>
        <App/>
    </Provider>,
    destination
);

console.log(1)

store.subscribe( ()=> {
console.log("-------------------------")
let s = store.getState()
console.log("STATE = " + s)
for (var k in s) {
    if (s.hasOwnProperty(k)) {
        console.log("k = " + k + "; value = " + s[k]);
    }
}
})

store.dispatch({
        type: types.LOAD_USER_NAME,
        userName : "Oppps1"
})

我的减速机:

import types from './../constants/actions'

export default function userNameReducer (state = {userName : 'N/A'}, action) {
console.log('inside reducer');
switch (action.type) {
    case types.LOAD_USER_NAME:
        console.log("!!!!!!!!!!!!!!!")
        console.log("action.userName = " + action.userName)
        for (var k in state) {
            if (state.hasOwnProperty(k)) {
                console.log("k = " + k + "; value = " + state[k]);
            }
        }
        return action.userName;
    default:
        return state
}
}

执行后在控制台中的结果:

【问题讨论】:

  • 你的 reducer 应该是纯函数,所以去掉副作用(console.log 的东西)
  • @IslamIbakaev 谢谢你的推荐,但它已经解决了这个问题
  • 你的意思是它现在可以正常工作了吗?
  • @IslamIbakaev -- 我认为他们的意思不是,它确实没有解决问题 -- 而且它与问题完全无关。

标签: javascript reactjs redux


【解决方案1】:

TLDR:停止使用 combineReducers 并将您的减速器直接传递给 createStore。使用import reducer from './foo' 而不是import * from './foo'

默认导入/导出示例,无combineReducers

// foo.js
function reducer(state, action) { return state; }
export default reducer;

----

// index.js
import myReducer from './foo';

combineReducers 为例

// foo.js
export default (state, action) => { ... }

----

// bar.js
export default (state, action) => { ... } 

----

// index.js
import foo from './foo';
import bar from './bar';

const store = createStore(combineReducers({
    foo,
    bar,
});

createStore(预加载状态)的第二个参数必须与您的组合减速器具有相同的对象结构。 combineReducers 接受一个对象,并将对象中提供的每个 reducer 应用到相应的 state 属性。现在您正在使用export default 导出reducer,它被转换为module.exports.default = yourReducer 之类的东西。当你导入reducer时,你会得到module.exports,它等于{default: yourReducer}。您的预加载状态没有 default 属性,因此 redux 抱怨。如果你使用import reducer from './blabla',你会得到module.exports.default,它等于你的reducer。

这里有更多关于 ES6 模块系统如何工作的信息,来自MDN

阅读来自 redux 的 combineReducers 文档也可能有所帮助。

【讨论】:

  • 谢谢你,你说的很对,问题出在我的reducer中的字default
  • 谢谢@eugene 的解释
【解决方案2】:

或者只是:

import yesReducer from './yesReducer';

const store = createStore(combineReducers({
    yesReducer,
    noReducer: (state = {}) => state,
});

【讨论】:

    【解决方案3】:
    import * as reducers from './reducers'
    

    是一种避免核心代码依赖于各种功能实现的好方法。

    为了让它工作,你必须指定reducer的名字和你的store key userName一样。这可以通过这种方式实现:

    在 reducers 文件夹中的 index.js 中,执行

    export { userNameReducer as userName } from "./UserNameReducer"
    export { otherReducer as other } from "./OtherReducer"
    

    另一种方法是直接将导出的reducer重命名为与存储键相同。

    【讨论】:

      猜你喜欢
      • 2019-09-05
      • 2020-03-04
      • 1970-01-01
      • 1970-01-01
      • 2018-03-21
      • 2020-01-21
      • 2021-02-22
      • 2014-12-18
      • 2020-03-08
      相关资源
      最近更新 更多