0

I have made a function that maps through the number of "steps" input, I think I have given each component unique keys but the console says otherwise. why is this? Another issue I'm having with this project is the title field doesn't update correctly but I can't work out why. Here is my code.

export default function App() {
  //number of steps required
  const [numberOfSteps, setNumberOfSteps] = useState(0);

  //number of steps to array to map through
  const stepsMap = Array.apply(
    null,
    Array(numberOfSteps).fill({ title: "", body: "" })
  );

  //steps array to object
  let stepsObject = { ...stepsMap };

  //updates title text
  const updateTileArray = (index, titleEventData) => {
    const stepsObjectData = { ...stepsObject };
    stepsObject = {
      ...stepsObjectData,
      [index]: { ...stepsObjectData[index], title: titleEventData }
    };
  };

  //updates quill text body
  const updateRichTextArray = (index, richTextEventData) => {
    const stepsObjectData = { ...stepsObject };
    stepsObject = {
      ...stepsObjectData,
      [index]: { ...stepsObjectData[index], body: richTextEventData }
    };
  };

  return (
    <div className="App">
      <TextField
        type="number"
        label="Number of steps"
        value={numberOfSteps}
        InputProps={{ inputProps: { min: 0 } }}
        onChange={(e) => setNumberOfSteps(Number(e.target.value))}
      />
      {stepsMap.map((_, index) => (
        <>
          <Typography key={"heading" + index}>Step: {index + 1}</Typography>
          <TextField
            key={"title" + index}
            type="text"
            label="Title"
            value={stepsObject[index]?.title}
            onChange={(titleEventData) =>
              updateTileArray(index, titleEventData.target.value)
            }
          />
          <ReactQuill
            key={"quill" + index}
            theme="snow"
            value={stepsObject[index]?.body}
            onChange={(richTextEventData) =>
              updateRichTextArray(index, richTextEventData)
            }
          />
        </>
      ))}
    </div>
  );
}

Code Sandbox

lukeet
  • 461
  • 1
  • 4
  • 22
  • Does this answer your question? [Can I add a key prop to a React fragment?](https://stackoverflow.com/questions/59390955/can-i-add-a-key-prop-to-a-react-fragment) – Martin Apr 28 '21 at 12:17
  • 1
    What is the console warning? maybe you can convert the fragment `<>` into `
    ` or `` and provide `key` on it.
    – Hashir Hussain Apr 28 '21 at 12:17
  • Thank you any answers to the second part of my question? – lukeet Apr 28 '21 at 12:21

2 Answers2

2

The key should be on the fragment, you can do it like this:

{stepsMap.map((_, index) => (
        <React.Fragment key={index}>
          <Typography>Step: {index + 1}</Typography>
          <TextField
            type="text"
            label="Title"
            value={stepsObject[index]?.title}
            onChange={(titleEventData) =>
              updateTileArray(index, titleEventData.target.value)
            }
          />
          <ReactQuill
            theme="snow"
            value={stepsObject[index]?.body}
            onChange={(richTextEventData) =>
              updateRichTextArray(index, richTextEventData)
            }
          />
        </React.Fragment>
      ))}
Driesigner
  • 31
  • 3
  • Thank you that seems to stop the complaining! but the ReactQuill element still seems to rerender when I press any buttons etc? – lukeet Apr 28 '21 at 12:21
  • Also can you work out why the title doesn't update correctly? – lukeet Apr 28 '21 at 12:22
0

First you should use <React.Fragment> to pass key prop. Second your code has two problems regarding title.

  1. stepsObject should be a state variable that will handle re-rendering of the component.
  2. You should concatenate the previous value of title with latest value in updateTileArray function.
Hashir Hussain
  • 614
  • 4
  • 8
  • 27
  • Thank you would you mind providing an example I don't quite understand what you mean? – lukeet Apr 28 '21 at 12:30
  • `const updateTileArray = (index: number, titleEventData: string) => { const stepsObjectData = { ...stepsObject } const titleConcat = stepsObjectData[index].title.concat( titleEventData ) stepsObject = { ...stepsObjectData, [index]: { ...stepsObjectData[index], title: titleConcat }, } console.log(stepsObject[index].title) }` – lukeet Apr 28 '21 at 12:41
  • this seems to work but the value is not updated? – lukeet Apr 28 '21 at 12:41
  • Here is my new code what do you think? https://codesandbox.io/embed/kind-buck-shg2t?fontsize=14&hidenavigation=1&theme=dark – lukeet Apr 28 '21 at 13:56
  • for some reason my sandbox link didn't send – lukeet Apr 28 '21 at 14:02