三行代码  ›  专栏  ›  技术社区  ›  Shaurya Atri

已删除组件的React状态获取状态

  •  0
  • Shaurya Atri  · 技术社区  · 3 月前

    我正在构建一个react应用程序,在该应用程序中,我需要通过单击“+”图标添加更多输入字段,并通过单击“x”图标删除字段。我正在利用react状态来处理这个项目。

    当我尝试使用“x”按钮删除组件时,会出现我所面临的问题。假设我有三个输入字段,如下所示:

    (id = 1) value = val1
    (id = 2) value = val2
    (id = 3) value = val3
    

    当我删除id=2的输入字段时,我希望获得如下所示的状态:

    (id = 1) value = val1
    (id = 3) value = val3
    

    但我获得的信息如下:

    (id = 1) value = val1
    (id = 3) value = val2
    

    以下是我的代码的简化版本:

    let count = 1;
    
    export default function Display() {
      //idArray stores the id of each of the input fields I have. It's initial state is set as []
      const {idArray, setIdArray} = useContext(Context);
    
      let components = idArray.map((id) => {
        return (
          <Component id={id} />
        );
      })
    
      const [description, setDescription] = useState("");
    
      return (
        <>
          <div id="component-1">
            <input
              className="className"
              id="1"
              type="text"
              onChange={({detail}) => setDescription(detail.value)}
              value={description} placeholder="Enter description"
            />
            {components}
          </div>
          <button
            iconName="add-plus"
            onClick={() => {
              count++;
              setIdArray(previousIdArray => [...previousIdArray, count]);
            }}
          />
        </>
      )
    }
    

    以下是组件的简化代码:

    export default function Component(props) {
      const { idArray, setIdArray } = useContext(Context);
    
      function removeRow(id, idArray, setIdArray) {
        const newArray = idArray.filter((i) => i !== id);
        setIdArray(newArray);
      }
    
      const [description, setDescription] = useState("");
    
      return (
        <div id={props.id}>
          <input
            className="className"
            id={props.id}
            type="text"
            onChange={({detail}) => setDescription(detail.value)}
            value={description} placeholder="Enter description"
          />
          <button
            iconName="cross"
            onClick={() => removeRow(props.id, idArray, setIdArray)}
          />
        </div>
      );
    }
    

    当我删除id=2的字段时,我希望id=3的状态值保持为val3。感谢任何关于为什么没有发生这种情况以及如何解决的线索。

    我提到 this 正如你所看到的,我使用count变量为代码中的组件提供了一个唯一的id,所以这应该不是问题。

    3 回复  |  直到 3 月前
        1
  •  1
  •   Drew Reese    3 月前

    您的映射中缺少React键 Component 组件。React又回到使用数组索引作为键,当您从数组中间移除一个元素时,索引不会改变,因此React键也不会改变。实际上,从React的角度来看,只有数组长度发生了变化,所以渲染的元素少了一个。

    export default function Display() {
      const [idArray, setIdArray] = useState([]);
      const [description, setDescription] = useState("");
    
      const handleChange = (event) => {
        setDescription(event.target.value);
      };
    
      return (
        <>
          <div id="component-1">
            <input
              className="className"
              id="1"
              type="text"
              onChange={handleChange}
              value={description}
              placeholder="Enter main description"
            />
            {idArray.map((id) => {
              return (
                <Component
                  key={id} // <-- Use appropriate React key
                  id={id}
                  idArray={idArray}
                  setIdArray={setIdArray}
                />
              );
            })}
          </div>
          <button
            iconName="add-plus"
            onClick={() => {
              count++;
              setIdArray((previousIdArray) => [...previousIdArray, count]);
            }}
          >
            +
          </button>
        </>
      );
    }
    
        2
  •  0
  •   Asad Koths    3 月前

    由于removeRow函数正在传递 shallow copy 以设置IdArray。你可以阅读更多关于如何 filter() 在这里工作。

    为了决定组件是否需要重新渲染(对于非基元类型),react通过 "shallow comparison"

    使用以下removeRow方法可能会得到更好的结果:

    function removeRow(id, idArray, setIdArray){
            const newArray = idArray.filter((i) => i !== id);
            setIdArray([newArray]);
        }
    
        3
  •  0
  •   Mansour Qaderi    3 月前

    我完全复习了你的技巧,如果你愿意,我建议你新的技巧。 我希望这对你有用

    export default function Display() {
    // in idArray I saved the description of each component, you can renamed it  
    // to descriptionArray
    const [idArray, setIdArray] = useState(Context);
     // in description I saved the new input value
    const [description, setDescription] = useState("");
    
    let components = idArray.map((description, index) => {
    // I passed index as ID and its description to the component
      return (
        <Component
         key={index}
         id={index.toString()}
         description={description}
         idArray={idArray}
         setIdArray={setIdArray}
        />
       );
     });
    
    return (
     <>
      <div id="component-1">
        <input
          className="className"
          id="1"
          type="text"
          onChange={(e) => setDescription(e.target?.value)}
          value={description}
          placeholder="Enter description"
        />
        {components}
      </div>
      <button
        onClick={() => {
          // I added the new description to the array
          setIdArray((previousIdArray) => [...previousIdArray, description]);
          // after saved new description, I cleaned the input
          setDescription("");
        }}
      >
        add
       </button>
     </>
     );
    }
    

    和你的 Component 组成部分

    function Component({
     id,
     description,
     idArray,
     setIdArray,
    }) {
    function removeRow() {
      const newArray = idArray.filter((_, index) => index !== Number(id));
      setIdArray([...newArray]);
    }
    
    const _changeDescription = (e) => {
      // I saved the new description in the array
      idArray[Number(id)] = e.target.value;
      setIdArray([...idArray]);
    };
    
    return (
      <div id={id}>
       <input
         className="className"
         id={id}
         type="text"
         onChange={_changeDescription}
         value={description}
         placeholder="Enter description"
      />
      <button onClick={() => removeRow()}>remove</button>
     </div>
     );
    }
    
    推荐文章