类型错误:state不可迭代。

3

我刚接触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);
2个回答

3

初始状态是一个对象,其中包含一个contactReducer属性,它是联系人数组。

我确定您刚刚指定了错误的默认状态值。

而不是

state = { contactReducer: initialState }

你可能想要
state = initialState

所有的reducer现在都会正确地将状态作为一个数组来指定/更新。

由于contactReducer reducer已经与另一个reducer合并并提供给store,因此这个操作将状态切片嵌套在您所合并的key下。

const reducer = combineReducers({
  login: authReducer,
  contactInfo: contactReducer, // <-- this
});

现在访问不再只是通过state.X,而是通过state.contactInfo.X

const mapStateToProps = (state) => ({
  contacts: state.contactInfo,
});

0

然而,在使用过滤器删除联系人的情况下可能会出现问题。 传递给过滤器的回调函数应该只返回 true 或 false,基于此它将被包含或不包含在结果数组中,但你似乎返回了 null 或对象。

更正后:

case "DELETE_CONTACT":
    const contactFilter = state.filter((contact) =>
      contact.id !== action.payload
    );
    state = contactFilter;
    return state;

上述过滤器将在id不相等时返回true,这意味着它将被考虑或false,这意味着它不会包含在结果数组中。
此外,在更新的情况下,您需要使用以下映射函数替换过滤器:
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;
}
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接