我正在建立一个任务管理器应用程序使用Redux工具包来管理状态.电路板切片的InitialState中的active Board属性.当我将其导入到编辑页面时,我能够编辑输入中的boardName属性,但不能编辑active Board对象内的Columns数组中的任何文本.我一直收到一个错误

"无法为对象的只读属性‘board’赋值

来自active Board对象的Columns数组被传递到"Columns"useState挂钩中.奇怪的是,当我将一个数组硬编码到useState钩子上时,我能够编辑每一列输入.任何帮助都将不胜感激.

EditBoardModal.jsx

import React, {useState} from 'react';
import {useDispatch, useSelector} from "react-redux";
import {editBoard} from "../../reducers/board/boardSlice";
import {hideModal} from "../../reducers/modal/modalSlice";
import Button from "../Button/Button";
import "./EditBoardModal.scss";

const EditBoardModal = () => {
  const dispatch = useDispatch();
  const {activeBoard} =  useSelector(store => store.board);
  const [boardName,
    setBoardName] = useState(activeBoard.name);
  const [columns,
    setColumns] = useState([...activeBoard.columns]);

  const nameChangeHandler = (e) => {
    setBoardName(e.target.value)
  }

  const columnsChangeHandler = (i, e) => {
    let columnsValues = [...columns];
    columnsValues[i][e.target.name] = e.target.value;
    console.log(columnsValues[0][e.target.name]);
    setColumns(columnsValues);
  }


  return (
    <div className="edit-board-modal">
      <h3 className="edit-modal-title">Edit Board</h3>
      <div className="edit-board-name-div">
        <label>Board Name</label>
        <input
          value={boardName}
          onChange={nameChangeHandler}
          className="edit-task-title"
          type="text"
          name="edit board name"
          placeholder="e.g. Web Design"/>
      </div>
      <div className="edit-board-columns-div">
        <label>Board Columns</label>
        {columns.map((column, index) => (
          <div className="edit-columns-item-div" key={index}>
            <input
             onChange={e => columnsChangeHandler(index, e)}
              className="edit-column-input"
              type="text"
              name="board"
              value={column.board}
              placeholder="e.g. Web Design"/>
            <svg onClick={() => deleteColumn(index)} key={index} width="15" height="15" xmlns="http://www.w3.org/2000/svg">
              <g fill="#828FA3" fillRule="evenodd"><path d="m12.728 0 2.122 2.122L2.122 14.85 0 12.728z"/><path d="M0 2.122 2.122 0 14.85 12.728l-2.122 2.122z"/></g>
            </svg>
          </div>
        ))}
      </div>

      <Button
        onClick={() => dispatch(hideModal())}
        text={"+ Add New Column"}
        className={"add-column-subtask"}/>
      <Button
        onClick={() => {
          dispatch(hideModal())
          dispatch(editBoard(boardName));
        }}
        text={"Save Changes"}
        className={"create-save-changes"}/>

    </div>
  )
}

export default EditBoardModal

boardSlice.js

import {createSlice} from "@reduxjs/toolkit";

const boardSlice = createSlice({
  name: "board",
  initialState: {
    boards: [],
    activeBoard: null
  },
  reducers: {
    setActiveBoard: (state, {payload}) => {
      const getBoardByID = state.boards.find(el => el.id === payload);
      state.activeBoard = getBoardByID;
    },
    addBoard: (state, {payload}) => {
      const newBoard = {
        id: payload.id,
        name: payload.name,
        columns: payload.columns
      }
      if (state.boards.length === 0) {
        state.activeBoard = newBoard;
      }
      state.boards.push(newBoard);
    },
    editBoard: (state, {payload}) => {
      state.activeBoard.name = payload;
    },
    deleteCurrentBoard: (state, {payload}) => {
      const deletedBoard = state.boards.filter(item => item.id !== state.activeBoard.id);

      state.boards = deletedBoard;

      state.activeBoard = state.boards[0];
    },
    addColumn: (state, {payload}) => {
      state.activeBoard.columns.push(payload)
    }

  }
});

export const {
  addBoard,
  setActiveBoard,
  deleteCurrentBoard,
  addColumn,
  editBoard
} = boardSlice.actions;

export default boardSlice.reducer;

推荐答案

columns状态是activeBoard.columns数组的浅表副本,但元素仍然是对片中保存的原始数组的引用.

const [columns, setColumns] = useState([...activeBoard.columns]);

columnsChangeHandler函数还创建columns数组的浅表副本,但同样,数组元素仍然是对切片中原始数组的原始引用.columnsChangeHandler正试图改变这些引用.

const columnsChangeHandler = (i, e) => {
  let columnsValues = [...columns]; // <-- copy of array, but not elements
  columnsValues[i][e.target.name] = e.target.value; // <-- mutate element
  setColumns(columnsValues);
}

在更新react 状态时,您必须浅复制正在更新的101状态(and nested state).使用Array.prototype.map浅复制数组,并为匹配的索引创建新的对象引用,浅复制元素并重写相应的属性.

例子:

const columnsChangeHandler = (i, e) => {
  const { name, value } = e.target;
  setColumns(columns => columns.map((el, index) => index === i
    ? {
      ...el,
      [name]: value,
    }
    : el
  ));
}

Javascript相关问答推荐

如何在RTK上设置轮询,每24小时

如何在Angular中插入动态组件

将本机导航路由react 到导航栏中未列出的屏幕?

变量的值在Reaction组件中的Try-Catch语句之外丢失

无法使用单击按钮时的useState将数据从一个页面传递到另一个页面

未定义引用错误:未定义&Quot;而不是&Quot;ReferenceError:在初始化&Quot;之前无法访问';a';

Next.js服务器端组件请求,如何发送我的cookie token?

在forEach循环中获取目标而不是父对象的属性

如何在Svelte中从一个codec函数中调用error()?

获取';无法解决导入和导入";slick-carousel/slick/slick-theme.css";';错误

如何限制显示在分页中的可见页面的数量

expo 联系人:如果联系人的状态被拒绝,则请求访问联系人的权限

打字脚本中方括号符号属性访问和拾取实用程序的区别

是否可以将Select()和Sample()与Mongoose结合使用?

如何在一个对象Java脚本中获取不同键的重复值?

如何在独立的Angular 应用程序中添加Lucide-Angel?

使用jQuery每隔几秒钟突出显示列表中的不同单词

Reaction:从子组件调用父组件中的函数

Qualtrics联合实验脚本随机化条件

在一次操作中使用多个addToSet不适用于多个数组