我可以在React/Redux Toolkit中编辑某些输入,但不能编辑其他输入

yftpprvb  于 2022-11-12  发布在  React
关注(0)|答案(2)|浏览(115)

我正在使用Redux Toolkit构建一个任务管理器应用程序来管理状态。板切片的initialState中的activeBoard属性。当我将其导入到编辑页面时,我可以编辑输入中的boardName属性,但不能编辑activeBoard对象中columns数组中的任何文本。我一直收到错误
“无法分配给对象的只读属性'board'
来自activeBoard对象的columns数组被传递到“columns”useState钩子。奇怪的是当我硬编码一个数组到useState钩子上时,我能够编辑每一列的输入。任何帮助都将不胜感激。

编辑板模式.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

板切片.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;
sxissh06

sxissh061#

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状态时,必须浅复制正在更新得***所有**状态( 与嵌套状态 *).使用Array.prototype.map浅复制数组,并为匹配得索引创建新得对象引用,浅复制元素并重写相应得属性.
示例:

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

u5rb5r592#

当您尝试变更已冻结对象的属性,或已使用Object定义属性时,通常会发生这个错误。
单击此处了解更多信息:https://bobbyhadz.com/blog/javascript-cannot-assign-to-read-only-property-of-object

相关问题