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.
- 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 secondconsole.log()returns an array of length 1 (it should be empty) - If there are more than two blocks in the array, no matter which
indexI 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
setBlockswill not immediately update the state. It won't update until the component rerenders.useCallbackhook for definingremoveBlockfunctionblockson each render usinguseEffectand it's not updating. So I think that means it's not even updating the state? And still unclear to me whyblocksfirst logs toundefinedin the function even though I can see it in the viewindexas thekeywhen rendering the blocks. You can't do that for mutable lists, each block needs its own unique identifier as thekeyprop