Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
320 views
in Technique[技术] by (71.8m points)

reactjs - Removing item from state array in React

I have a function component in React called Spec which has a list of Blocks with the below interface. Spec maintains a list of blocks that users an add to, edit, or delete.

Issue: The delete action is not working as intended.

  1. If there's only one block, then it does nothing, and the first console.log() in the function returns an empty array (it should be length 1), and the second console.log() returns an array of length 1 (it should be empty)
  2. If there are more than two blocks in the array, no matter which index I delete, the final (n-1) elements of the array are deleted

Can anyone see what I'm doing wrong?

//types.d.ts

interface Block extends Array {
  type: string,
  block: StoryBlock | MarkdownBlock
}

interface StoryBlock {
  title: string,
  description: string,
  visibility: boolean,
  status: string,
}

interface MarkdownBlock {
  title: string,
  description: string,
  visibility: boolean,
}
const Spec: React.FC<OptSpecProps> = (props) => {
    const [blocks, setBlocks] = useState<Block[]>([]);

...

  const addBlock = (type: string) => {
    let blockSeed;
    switch (type) {
      case "story":
        blockSeed = emptyStoryData;
        break;
      case "markdown":
        blockSeed = emptyMarkdownText
        break;
      default:
        blockSeed = emptyMarkdownText
        break;
    }
    const newBlockArray = blocks.concat({type: type, block: blockSeed})
    setBlocks([...newBlockArray]);
  };

  const removeBlock = (index: number) => {
    console.log(blocks) //This logs an empty array
    const newBlockArray = blocks.splice(index, 1);
    console.log(newBlockArray) // this logs the correct array
    setBlocks([...newBlockArray])
  }

  const updateBlock = (index: number, type: string, block: StoryBlock | MarkdownBlock) => {
    let newBlockArray: Block[] = blocks;
    newBlockArray[index] = {type: type, block: block};
    newBlockArray.forEach((block_itr: Block, i: number) => {
      if (i === index) {
        block_itr.block = block
        block_itr.block.visibility = true
      } else {
        block_itr.block.visibility = false
      }
    })
    setBlocks([...newBlockArray]);
  };

Here is a link to a simplified component sandbox, but it looks from the comments we've identified the issue


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You are setting the new block to the result of the splice() method, although, that method mutates the array in place and returns the removed elements. Instead, you should clone the array and then splice it

const removeBlock = (index: number) => {
  const newBlockArray = [...blocks];
  newBlockArray.splice(index, 1);
  setBlocks(newBlockArray)
}

P.S. Be aware that the above performs a shallow copy of the array, but it should not be a problem in this case.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...