Florie Anstett
Florie Anstett

Reputation: 1423

in react when I remove a dynamic input, the input does not show the right value on the browser

I'm new in React and i'm learning to use it with hooks.
I tried to put dynamics inputs which works so far but I have a display problem.
If I delete the last input, no problem but if I delete others inputs than the last one then the correct values does not show on the browser.
For example I add 2 inputs.
first one titled "one" and second titled "two".
If I delete "one", the remain input on screen shows "one" or it should show "two".
However, in the array where I collect the inputs infos, there is the correct remaining input.
(see screenshot).
How can I do to show the correct title in the input on the browser ?

const [titleSelected, setTitleSelected] = useState(true);
const [questionType, setQuestionType] = useState([]);
const [questionsTitle, setQuestionsTitle] = useState([]);


  {questionType ? (
        questionType.map((questions, index) => {
          return (
            <div key={index} className="questions">
              <div className={questions === "texte" ? "orange" : "red"}>
                <span>{questions === "texte" ? "1" : "2"}</span>
                <img src={Minus} alt="" />
                <img
                  src={questions === "texte" ? FileWhite : StarWhite}
                  alt=""
                />
              </div>
              <input
                type="text"
                placeholder="Ecrivez votre question"
                onChange={(event) => {
                  let tab = [...questionsTitle];
                  // si index de l'objet existe on update index de l'objet par index sinon on push le nouvel objet
                  let tabIndex = tab.findIndex(
                    (element) => element.index === index
                  );
                  if (tabIndex !== -1) {
                    tab[tabIndex].type = questionType[index];
                    tab[tabIndex].title = event.target.value;
                  } else {
                    tab.push({
                      index: index,
                      type: questionType[index],
                      title: event.target.value,
                    });
                  }
                  setQuestionsTitle(tab);
                }}
              ></input>
              <div>
                <img src={ChevronUp} alt="move up" />
                <img src={ChevronDown} alt="move down" />
                <img
                  src={SmallTrash}
                  alt="delete question"
                  onClick={() => {
                    let tab = [...questionType];
                    tab.splice(index, 1);
                    setQuestionType(tab);
                    let tabTitle = [...questionsTitle];
                    tabTitle.splice(index, 1);
                    setQuestionsTitle(tabTitle);
                  }}
                />
              </div>
            </div>
          );
        })
      ) : (
        <div></div>
      )}
      <div className="questionType">
        <div
          className="addText"
          onClick={() => {
            let tab = [...questionType];
            tab.push("texte");
            setQuestionType(tab);
          }}
        >
          <img src={File} alt="" />
          <p>Ajouter une question "Texte"</p>
        </div>
        <div
          className="addNote"
          onClick={() => {
            let tab = [...questionType];
            tab.push("note");
            setQuestionType(tab);
          }}
        >
          <img src={Star} alt="" />
          <p>Ajouter une question "Note"</p>
        </div>
      </div>

screenshot

Upvotes: 2

Views: 1755

Answers (1)

Drew Reese
Drew Reese

Reputation: 202836

Issues

You are mutating the array you are mapping so don't use the array index as the react key. If you remove the ith element all the elements shift up, but the keys remain unchanged and react bails on rerendering.

Lists & Keys

questionType.map((questions, index) => (
  <div key={index} className="questions">
    ...
  </div>
)

The array index as a React key doesn't "stick" to the element object it "identifies".

You've also some state object mutation occurring.

tab[tabIndex].type = questionType[index];
tab[tabIndex].title = event.target.value;

This is masked by the shallow copy let tab = [...questionsTitle];.

Solution

Select a react key that is unique among siblings and related to the elements, like an id.

Since you enclose the index when adding new elements to the array I think you can resolve the key issue by simply using the saved index.

questionType.map((questions, index) => (
  <div key={questionsTitle[index].index} className="questions">
    ...
  </div>
)

This may be a little confusing so I suggest changing the property to id.

questionType.map((questions, index) => (
  <div key={questionsTitle[index].id} className="questions">
    ...

    <input
      ...
      onChange={event => {
        ...
        tab.push({
          id: index,
          type: questionType[index],
          title: event.target.value,
        });
        ...
      }}
    />

    ...
  </div>
)

A further suggestion is to avoid using the array index at all. The following code can quickly get out of sync when the array index being mapped doesn't align to the saved index in the element.

let tabIndex = tab.findIndex(element => element.index === index); 

Generate id's for your elements and use that to determine if elements should be updated or appended. When updating make sure to shallow copy the array and then also shallow copy the element object being updated.

Upvotes: 2

Related Questions