组件尺寸更改时状态未清除

问题描述 投票:0回答:1

我正在遍历基于多个数组创建的几个组件。当我单击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

reactjs
1个回答
1
投票

如果列表组件中有项目,并且项目必须从列表中接收功能以更改或删除项目,则最好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(() => FoodList(propsWithActions), [propsWithActions]);
});
const FoodList = ({ 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 Foos = 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 Foos;
© www.soinside.com 2019 - 2024. All rights reserved.