我是React和Redux的新手。试图理解基础知识并做一些简单的例子,但是我在这个问题上停留了超过一天,我找不到解决方法。我想我的错误是愚蠢的错误。
问题是我无法打印用户数组。调试时,变量 users 会加载所有正确的ID和用户,但是在执行<li key={id}>{name}</li>
3次之后,它返回到forEach并给出以下异常: 未捕获的TypeError:无法读取未定义 users 的属性'forEach' 。而且我还收到与PropTypes相对应的错误: 提供给HomePage的类型数组无效的prop用户,预期对象
代码如下:
store / configureStore.js
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers/index';
const initialState = {};
const middleware = [thunk];
const store = createStore(rootReducer, initialState, compose(
applyMiddleware(...middleware),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
));
export default store;
reducers / index.js
import { combineReducers } from 'redux';
import userReducer from './userReducer';
//import groupReducer from './groupReducer';
export default combineReducers({
user: userReducer
});
reducers / userReducer.js
import { GET_USERS, ADD_USER, DELETE_USER } from '../actions/types';
const initialState = {
users: [
{ id: 1, name: 'brunao'},
{ id: 2, name: 'flavio'},
{ id: 3, name: 'dudu'}
]
};
export default function(state = initialState, action) {
switch (action.type) {
case GET_USERS:
return [
...state
];
default:
return state;
}
}
actions / usersAction.js
import { GET_USERS, ADD_USER, DELETE_USER } from './types';
export const getUsers = () => {
return {
type: GET_USERS
};
};
components / HomePage.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { getUsers } from '../actions/usersActions';
import PropTypes from 'prop-types';
class HomePage extends Component {
componentDidMount() {
this.props.getUsers();
}
render() {
const { users } = this.props.user;
return(
<div>
<h3>Users</h3>
<ul>
{users.forEach(({id, name}) => (
<li key={id}>{name}</li>
))}
</ul>
</div>
);
}
}
HomePage.propTypes = {
getUsers: PropTypes.func.isRequired,
user: PropTypes.object.isRequired
}
const mapStateToProps = (state) => ({
user: state.user
});
export default connect(mapStateToProps, { getUsers })(HomePage);
答案 0 :(得分:2)
您在减速器中返回了错误的状态。您的相关代码:
export default function(state = initialState, action) {
switch (action.type) {
case GET_USERS:
return [
...state
];
default:
return state;
}
}
在这里,状态是一个对象,但是您正在通过传播它将其以数组形式返回。因此,您的状态将被破坏。
尝试一下:
case GET_USERS:
return state;
正如@Idan Dagan在他的回答中指出的那样,实际上,我们不会在化简器中改变状态。我刚刚提出了这个建议,因为您只是在玩耍学习Redux,我们将在这里返回原始状态,仅此而已。但是,这是一种返回状态的合适且更好的方法:
case GET_USERS:
return { ...state };
以下是有效的代码:https://codesandbox.io/s/k5ymxwknpv
我还按照@Idan Dagan的建议,再次用forEach
更改了map
。我还没意识到。 forEach
在这里不合适,因为实际上它不返回任何内容。您想在React中映射数组并渲染它们。
此外,您的州名令人困惑:) user.users
有点奇怪,您可能会想一个更好的州。
评论后编辑
您的GET_USERS操作实际上已被击中,但是您在代码中检查了它是否错误。您正在做
export default function(state = initialState, action) {
switch (action.type) {
case GET_USERS:
return Object.assign({}, state);
default:
return {
users: [
{ id: 1, name: "TEST" },
{ id: 2, name: "TEST1" },
{ id: 3, name: "TEST2" }
]
};
}
}
这里发生了什么? Redux的第一个动作是INIT
。这是您状态的初始化。现在,由于没有任何动作,减速器将达到默认情况并返回TEST。现在,您的状态成为该TEST数据。然后您的GET_USERS
被击中,并且您返回一个新对象,该对象合并了处于测试状态的状态。步骤如下:
First, state is the `initialState` -> `INIT` runs and hits the default case
State is now TEST one -> GET_USERS hit and returns the `state` which is TEST one
You see the TEST one.
您如何测试自己的行为?只需将console.log
放入减速器中即可:
export default function(state = initialState, action) {
console.log("state",state);
console.log("action",action);
.....
,然后看到GET_USERS实际上被命中了。另一种选择是,不使用state
返回合并的对象,而是尝试使用initialState
合并它,或者使用传播算子通过使用initialState
返回一个新对象:
return return Object.assign({}, initialState);
或
return {...initialState}
最后一个选项使您更加了解我的第一个解释的工作原理。尝试将其返回给您的GET_USERS:
return {...state, users:[...state.users, {id:4, name: "foo"}]};
您将看到一个包含TEST数据的用户列表,但最后一个将是您的foo
。这说明了在默认情况下如果返回initialState
旁的任何内容,将如何释放state
。
最后的建议是,您可以使用Redux Dev Tools调试Redux开发。它是一个很棒的工具,除了调试以外,还可以做更多的事情。您可以轻松跟踪Redux的所有操作。
答案 1 :(得分:0)
我不确定您打算如何处理新状态。
但是您需要做一些更改:
export default function(state = initialState, action) {
switch (action.type) {
case GET_USERS:
return Object.assign({}, state);
default:
return state;
}
}
如redux docs中所述:
我们不改变状态。我们使用Object.assign()
创建一个副本。