TypeError: state is not iterable
TypeError: state is not iterable
我是 React js 的新手,我正在尝试创建联系人列表。您可以在其中添加联系人、更新联系人以及从联系人列表中删除联系人。但是,我正在尝试初始化我的联系人列表的状态,但是当我 运行 它时,它显示的联系人列表屏幕没有联系人列表的“initialState”。然后,当我尝试添加联系人时,它会抛出一个类型错误屏幕(状态不可迭代)。我该如何解决这个问题?
contactReducer.js:
const initialState = [
{ id: 0, name: "Raman Sharma", Level: " 20", Progress: "Master" },
{ id: 1, name: "Test Name", Level: " 25", Progress: "Master" },
];
export const contactReducer = (state = initialState , action) => {
switch (action.type) {
case "ADD_CONTACT":
state = [...state, action.payload];
return state;
case "DELETE_CONTACT":
const contactFilter = state.filter((contact) =>
contact.id === action.payload ? null : contact
);
state = contactFilter;
return state;
case "UPDATE_CONTACT":
const contactUpdate = state.filter((contact) =>
contact.id === action.payload.id
? Object.assign(contact, action.payload)
: contact
);
state = contactUpdate;
return state;
case "RESET_CONTACT":
state = [{ name: null, Level: null, Progress: null }];
return state;
default:
return state;
}
};
./client/AddContact/index.js
import React, { useState } from "react";
import { connect } from "react-redux";
import { useHistory } from "react-router";
import { toast } from "react-toastify";
const AddPost = ({ contacts, addContact }) => {
const [name, setName] = useState("");
// const [Level, setLevel] = useState("");
// const [Progress, setProgress] = useState("");
const history = useHistory();
const handleSubmit = (e) => {
e.preventDefault();
// const checkContactLevelExists = contacts.filter((contact) =>
// contact.Level === Level ? contact : null
//);
// const checkContactProgressExists = contacts.filter((contact) =>
// contact.Progress === Progress ? contact : null
//);
if ( !name) {
return toast.warning("Please fill in field!!");
}
// if (checkContactLevelExists.length > 0) {
// return toast.error("This Level already exists!!");
// }
// if (checkContactProgressExists.length > 0) {
// return toast.error("This Progress number already exists!!");
// }
const data = {
id: contacts.length > 0 ? contacts[contacts.length - 1].id + 1 : 0,
// Level,
name,
// Progress,
};
addContact(data);
toast.success("Player Added successfully!!");
history.push("/");
};
return (
<div className="container-fluid">
<h1 className="text-center text-dark py-3 display-2">Add Friend</h1>
<div className="row">
<div className="col-md-6 p-5 mx-auto shadow">
<form onSubmit={handleSubmit}>
<div className="form-group">
<input
className="form-control"
type="text"
placeholder="Full name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
{/* <div className="form-group">
<input
className="form-control"
type="Level"
placeholder="Level"
value={Level}
onChange={(e) => setLevel(e.target.value)}
/>
</div> */}
{/* <div className="form-group">
<input
className="form-control"
type="number"
placeholder="Progress"
value={Progress}
onChange={(e) => setProgress(e.target.value)}
/>
</div> */}
<div className="form-group">
<input
className="btn btn-block btn-dark"
type="submit"
value="Add Student"
/>
</div>
</form>
</div>
</div>
</div>
);
};
const mapStateToProps = (state) => ({
contacts: state,
});
const mapDispatchToProps = (dispatch) => ({
addContact: (data) => {
dispatch({ type: "ADD_CONTACT", payload: data });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(AddPost);
home.js
import React from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
const Friends = ({ contacts, deleteContact }) => {
return (
<div className="container">
<div className="row d-flex flex-column">
<Link to="/add" className="btn btn-outline-dark my-5 ml-auto ">
Add Friend
</Link>
<div className="col-md-10 mx-auto my-4">
<table className="table table-hover">
<thead className="table-header bg-dark text-white">
<tr>
<th scope="col">Id</th>
<th scope="col">Name</th>
<th scope="col">Level</th>
<th scope="col">Progess</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
{contacts.length > 0 ? (
contacts.map((contact, id) => (
<tr key={id}>
<td>{id + 1}</td>
<td>{contact.name}</td>
<td>{contact.Level}</td>
<td>{contact.Progress}</td>
<td>
<Link
to={`/edit/${contact.id}`}
className="btn btn-sm btn-primary mr-1"
>
Edit
</Link>
<button
type="button"
onClick={() => deleteContact(contact.id)}
className="btn btn-sm btn-danger"
>
Remove
</button>
</td>
</tr>
))
) : (
<tr>
<th>No contacts found</th>
</tr>
)}
</tbody>
</table>
</div>
</div>
</div>
);
};
const mapStateToProps = (state) => ({
contacts: state,
});
const mapDispatchToProps = (dispatch) => ({
deleteContact: (id) => {
dispatch({ type: "DELETE_CONTACT", payload: id });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(Friends);
初始状态是一个具有 contactReducer
属性 的对象,即联系人数组。
我确定您刚刚指定了错误的默认状态值。
而不是
state = { contactReducer: initialState }
你可能想要
state = initialState
现在所有的 reducer 都会正确地 specify/update 状态为数组。
由于 contactReducer
reducer 与另一个 reducer 组合并提供给商店,这将状态切片嵌套在您将它们组合在一起的键下。
const reducer = combineReducers({
login: authReducer,
contactInfo: contactReducer, // <-- this
});
现在是 state.contactInfo.X
.
,而不是仅通过 state.X
访问
const mapStateToProps = (state) => ({
contacts: state.contactInfo,
});
但是,在使用过滤器时删除联系人案例可能会出现问题。
传递给过滤器的回调应该 return true 或 false 仅基于它将包含或不包含在结果数组中,而不是你似乎 returned null 或 object.
更正:
case "DELETE_CONTACT":
const contactFilter = state.filter((contact) =>
contact.id !== action.payload
);
state = contactFilter;
return state;
如果 id 不相等,上面的过滤器将 return 为真,这意味着它会被考虑或为假,这意味着它不会被包含在结果数组中
另外,如果是Update,你需要用map函数替换filter,如下:
case "UPDATE_CONTACT":
const contactUpdate = state.map((contact) =>
contact.id === action.payload.id
? {...contact, ...action.payload}
: contact
);
state = contactUpdate;
return state;
此外,我将 contactReducer.js 更改如下:
const initialState = { contacts: [
{ id: 0, name: "Raman Sharma", Level: " 20", Progress: "Master" },
{ id: 1, name: "Test Name", Level: " 25", Progress: "Master" },
]};
export const contactReducer = (state = initialState , action) => {
switch (action.type) {
case "ADD_CONTACT":
return {contacts: [...state.contacts, action.payload]};
case "DELETE_CONTACT":
return {contacts: state.contacts.filter((contact) =>
contact.id !== action.payload
)};
case "UPDATE_CONTACT":
return {contacts: state.contacts.map((contact) =>
contact.id === action.payload.id
? {...contact, ...action.payload}
: contact
)};
case "RESET_CONTACT":
return {contacts: [{ name: null, Level: null, Progress: null }]};
default:
return state;
}
};
我是 React js 的新手,我正在尝试创建联系人列表。您可以在其中添加联系人、更新联系人以及从联系人列表中删除联系人。但是,我正在尝试初始化我的联系人列表的状态,但是当我 运行 它时,它显示的联系人列表屏幕没有联系人列表的“initialState”。然后,当我尝试添加联系人时,它会抛出一个类型错误屏幕(状态不可迭代)。我该如何解决这个问题?
contactReducer.js:
const initialState = [
{ id: 0, name: "Raman Sharma", Level: " 20", Progress: "Master" },
{ id: 1, name: "Test Name", Level: " 25", Progress: "Master" },
];
export const contactReducer = (state = initialState , action) => {
switch (action.type) {
case "ADD_CONTACT":
state = [...state, action.payload];
return state;
case "DELETE_CONTACT":
const contactFilter = state.filter((contact) =>
contact.id === action.payload ? null : contact
);
state = contactFilter;
return state;
case "UPDATE_CONTACT":
const contactUpdate = state.filter((contact) =>
contact.id === action.payload.id
? Object.assign(contact, action.payload)
: contact
);
state = contactUpdate;
return state;
case "RESET_CONTACT":
state = [{ name: null, Level: null, Progress: null }];
return state;
default:
return state;
}
};
./client/AddContact/index.js
import React, { useState } from "react";
import { connect } from "react-redux";
import { useHistory } from "react-router";
import { toast } from "react-toastify";
const AddPost = ({ contacts, addContact }) => {
const [name, setName] = useState("");
// const [Level, setLevel] = useState("");
// const [Progress, setProgress] = useState("");
const history = useHistory();
const handleSubmit = (e) => {
e.preventDefault();
// const checkContactLevelExists = contacts.filter((contact) =>
// contact.Level === Level ? contact : null
//);
// const checkContactProgressExists = contacts.filter((contact) =>
// contact.Progress === Progress ? contact : null
//);
if ( !name) {
return toast.warning("Please fill in field!!");
}
// if (checkContactLevelExists.length > 0) {
// return toast.error("This Level already exists!!");
// }
// if (checkContactProgressExists.length > 0) {
// return toast.error("This Progress number already exists!!");
// }
const data = {
id: contacts.length > 0 ? contacts[contacts.length - 1].id + 1 : 0,
// Level,
name,
// Progress,
};
addContact(data);
toast.success("Player Added successfully!!");
history.push("/");
};
return (
<div className="container-fluid">
<h1 className="text-center text-dark py-3 display-2">Add Friend</h1>
<div className="row">
<div className="col-md-6 p-5 mx-auto shadow">
<form onSubmit={handleSubmit}>
<div className="form-group">
<input
className="form-control"
type="text"
placeholder="Full name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
{/* <div className="form-group">
<input
className="form-control"
type="Level"
placeholder="Level"
value={Level}
onChange={(e) => setLevel(e.target.value)}
/>
</div> */}
{/* <div className="form-group">
<input
className="form-control"
type="number"
placeholder="Progress"
value={Progress}
onChange={(e) => setProgress(e.target.value)}
/>
</div> */}
<div className="form-group">
<input
className="btn btn-block btn-dark"
type="submit"
value="Add Student"
/>
</div>
</form>
</div>
</div>
</div>
);
};
const mapStateToProps = (state) => ({
contacts: state,
});
const mapDispatchToProps = (dispatch) => ({
addContact: (data) => {
dispatch({ type: "ADD_CONTACT", payload: data });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(AddPost);
home.js
import React from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
const Friends = ({ contacts, deleteContact }) => {
return (
<div className="container">
<div className="row d-flex flex-column">
<Link to="/add" className="btn btn-outline-dark my-5 ml-auto ">
Add Friend
</Link>
<div className="col-md-10 mx-auto my-4">
<table className="table table-hover">
<thead className="table-header bg-dark text-white">
<tr>
<th scope="col">Id</th>
<th scope="col">Name</th>
<th scope="col">Level</th>
<th scope="col">Progess</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
{contacts.length > 0 ? (
contacts.map((contact, id) => (
<tr key={id}>
<td>{id + 1}</td>
<td>{contact.name}</td>
<td>{contact.Level}</td>
<td>{contact.Progress}</td>
<td>
<Link
to={`/edit/${contact.id}`}
className="btn btn-sm btn-primary mr-1"
>
Edit
</Link>
<button
type="button"
onClick={() => deleteContact(contact.id)}
className="btn btn-sm btn-danger"
>
Remove
</button>
</td>
</tr>
))
) : (
<tr>
<th>No contacts found</th>
</tr>
)}
</tbody>
</table>
</div>
</div>
</div>
);
};
const mapStateToProps = (state) => ({
contacts: state,
});
const mapDispatchToProps = (dispatch) => ({
deleteContact: (id) => {
dispatch({ type: "DELETE_CONTACT", payload: id });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(Friends);
初始状态是一个具有 contactReducer
属性 的对象,即联系人数组。
我确定您刚刚指定了错误的默认状态值。
而不是
state = { contactReducer: initialState }
你可能想要
state = initialState
现在所有的 reducer 都会正确地 specify/update 状态为数组。
由于 contactReducer
reducer 与另一个 reducer 组合并提供给商店,这将状态切片嵌套在您将它们组合在一起的键下。
const reducer = combineReducers({
login: authReducer,
contactInfo: contactReducer, // <-- this
});
现在是 state.contactInfo.X
.
state.X
访问
const mapStateToProps = (state) => ({
contacts: state.contactInfo,
});
但是,在使用过滤器时删除联系人案例可能会出现问题。 传递给过滤器的回调应该 return true 或 false 仅基于它将包含或不包含在结果数组中,而不是你似乎 returned null 或 object.
更正:
case "DELETE_CONTACT":
const contactFilter = state.filter((contact) =>
contact.id !== action.payload
);
state = contactFilter;
return state;
如果 id 不相等,上面的过滤器将 return 为真,这意味着它会被考虑或为假,这意味着它不会被包含在结果数组中
另外,如果是Update,你需要用map函数替换filter,如下:
case "UPDATE_CONTACT":
const contactUpdate = state.map((contact) =>
contact.id === action.payload.id
? {...contact, ...action.payload}
: contact
);
state = contactUpdate;
return state;
此外,我将 contactReducer.js 更改如下:
const initialState = { contacts: [
{ id: 0, name: "Raman Sharma", Level: " 20", Progress: "Master" },
{ id: 1, name: "Test Name", Level: " 25", Progress: "Master" },
]};
export const contactReducer = (state = initialState , action) => {
switch (action.type) {
case "ADD_CONTACT":
return {contacts: [...state.contacts, action.payload]};
case "DELETE_CONTACT":
return {contacts: state.contacts.filter((contact) =>
contact.id !== action.payload
)};
case "UPDATE_CONTACT":
return {contacts: state.contacts.map((contact) =>
contact.id === action.payload.id
? {...contact, ...action.payload}
: contact
)};
case "RESET_CONTACT":
return {contacts: [{ name: null, Level: null, Progress: null }]};
default:
return state;
}
};