【问题标题】:State not clearing when the amout of component has changed组件数量发生变化时状态不清除
【发布时间】:2019-10-06 12:16:20
【问题描述】:

我正在循环基于多个数组创建的几个组件。当我单击delete 时,这会减少数组,从而减少组件的数量。

FooList.tsx

import React, { useState } from "react";

const FooList = props => {
  const [number, setNumber] = useState("");

  const deleteArray = () => {
    // Remove the component that was clicked
    props.setArray(prev => prev.filter(a => a !== props.current));
  };

  return (
    <>
      <input
        type="number"
        placeholder="Phone"
        onChange={e => setNumber(e.target.value)}
        value={number}
      />
      <button onClick={() => deleteArray()}>delete</button>
    </>
  );
};

export default FooList;

Foos.tsx

import React, { useState } from "react";
import FooList from "./FooList";

const Foos = props => {
  const [array, setArray] = useState([]);

  const addToarray = (id: number) => {
    const obj = { id };
    const a: any = array.concat(obj);
    console.log(a);
    setArray(a);
  };

  return (
    <>
      {array.map((a, index) => (
        <div key={index}>
          <FooList current={a} setArray={setArray} />
        </div>
      ))}
      <button onClick={() => addToarray(Math.random())}>add</button>
    </>
  );
};

export default Foos;

渲染

<Foos />

我希望当我输入一个值时,有多个值,当我按下 delete 时,该组件应该连同其输入的值一起被删除。

DEMO

【问题讨论】:

  • 使用索引作为键对于渲染 jsx 列表不是一个好主意,尤其是当您可以删除项目时。我会看看演示。
  • Here 是一个优化的更新示例,在不需要时不会重新渲染项目。
  • 太棒了。我以前从未使用过useMemo。我想现在是学习它的时候了。您可以将此添加为答案,我会接受。谢谢

标签: reactjs


【解决方案1】:

如果您的 List 组件具有 Items 并且 Items 必须从 List 接收函数以更改或删除项目,您最好 optimize 这些函数以防止重新渲染。

这是您优化的列表和项目的示例:

FooItem:

import React, { memo, useMemo } from "react";

//make this a pure component using React.memo
const FooItemContainer = memo(props => {
  const {
    remove,
    change,
    current: { id, val }
  } = props;
  //only logs for item(s) that actually change
  console.log("in item container for id:", id);
  //add events to props
  const propsWithActions = useMemo(
    () => ({
      change: e => change(id, e.target.value),
      remove: () => remove(id),
      val
    }),
    [change, remove, val, id]
  );

  return useMemo(() => FooItem(propsWithActions), [propsWithActions]);
});
const FooItem = ({ change, remove, val }) =>
  console.log("in item presentation", val) || (
    <>
      <input type="number" placeholder="Phone" onChange={change} value={val} />
      <button onClick={remove}>delete</button>
    </>
  );

export default FooItemContainer;

FooList:

import React, { useState, useEffect, useCallback } from "react";
import FooItem from "./FooItem";
//function to create unique id
const crateId = (num => () => num++)(1);
//do not re reference item callback functions
//  detailed explanation can be found here:
//  https://stackoverflow.com/a/58192552/1641941
function useEventCallback(fn) {
  //ref will never change during component life cycle
  const ref = React.useRef();

  //every time useEventCallback is called we set ref.current again.
  //  we can add fn as a dependency but if you see how Parent calls it
  //  it will have the same outcome because useEventCallback(()=>...)
  //  causes fn to be different every time anyway
  useEffect(() => {
    ref.current = fn;
  });
  //here we return a function that will never change during the component
  //  life cycle but what it does will change during it's life cycle
  //  because we keep mutating ref and resetting ref.current
  return useCallback(
    (...args) => ref.current.apply(void 0, args),
    [] //you can do [ref] here but linter knows ref will never change so no needfor it
  );
}

const FooList = props => {
  const [array, setArray] = useState([]);

  const addToarray = useEventCallback(() => {
    setArray(array.concat({ id: crateId(), val: "" }));
  });
  const remove = useEventCallback(id =>
    setArray(array.filter(item => id !== item.id))
  );
  const change = useEventCallback((id, val) =>
    setArray(array.map(item => (id !== item.id ? item : { ...item, val })))
  );

  return (
    <>
      <button onClick={addToarray}>add</button>
      {array.map(a => (
        <div key={a.id}>
          <FooItem current={a} remove={remove} change={change} />
        </div>
      ))}
    </>
  );
};

export default FooList;

【讨论】:

    猜你喜欢
    • 2020-10-21
    • 2021-07-09
    • 1970-01-01
    • 2021-06-12
    • 2022-07-29
    • 2023-03-31
    • 1970-01-01
    • 2023-01-19
    • 2012-01-17
    相关资源
    最近更新 更多