Managing array state

DEMO
When updating an array, first make a shallow copy with the spread operator, then modify it. Finally, set the state with this copy.
ColouredBlocks.jsx

const ColouredBlocks = () => {
  const [blocks, setBlocks] = useState(["#3B82F6", "#1D4ED8", "#6366F1"]);

  // find a colour that doesn't already exist in the array
  const getUnusedBlockColor = () => {
    return possibleColors.find((color) => !blocks.includes(color));
  };

  const addItem = (pos) => {
    if (blocks.length > 4) return; // limit number of blocks
    // copy array
    const newBlocks = [...blocks];
    // add new block to beginning
    if (pos === "start") newBlocks.unshift(getUnusedBlockColor());
    // add new block to end
    else if (pos === "end") newBlocks.push(getUnusedBlockColor());
    setBlocks(newBlocks);
  };

  const updateItem = (index) => {
    // copy array
    const newBlocks = [...blocks];
    // edit existing block
    newBlocks[index] = getUnusedBlockColor();
    setBlocks(newBlocks);
  };

  const deleteItem = (index) => {
    if (blocks.length === 1) return; // at least one block must exist
    // filter out the block with the selected index
    const newBlocks = blocks.filter((block, i) => i !== index);
    setBlocks(newBlocks);
  };

  return (
    <BlocksWrapper>
      <AddBtn onClick={() => addItem("start")} />
      {blocks.map((bgColor, index) => (
        <Block key={bgColor} style={{ "--bgColor": `${bgColor}` }}>
          <ControlBox>
            <EditBtn onClick={() => updateItem(index)} />
            <DeleteBtn onClick={() => deleteItem(index)} />
          </ControlBox>
        </Block>
      ))}
      <AddBtn onClick={() => addItem("end")} />
    </BlocksWrapper>
  );
};

Note: Code snippets do not include styling details unless they are the focus of the exercise.

Copyright © 2022 Explore React