【问题标题】:React Native infinite loop with object array in useEffect在 useEffect 中使用对象数组反应本机无限循环
【发布时间】:2022-11-11 01:25:07
【问题描述】:

在我的项目中,我需要从 Flatlist 中获取选定的项目并将它们传递给我的父组件。

我创建了一个像这样的本地状态:

const [myState, setMyState] = useState<IStateType[] | []>([])  

每次选择一个项目时,我都会尝试将其添加到我的 useEffect 中:

useEffect(() => {
    const result = myState.filter((el) => el.id !== item.id)
    if (isSelected) {
      setMyState([
        ...result,
        {
          propOne: 0,
          propTwo: 1,
          id: item.id,
         ...
        },
      ])
    } else {
      setMyState(result)
    }
  }, [isSelected])

但是我需要将 mySate 放在我的 useEffect 的依赖项中,以便在每次选择新项目时添加。如果我将它添加到 useEffect 依赖项中,它会导致无限循环 ^^
如何在聆听所有更改且不导致无限循环的情况下将每个新项目添加到我的数组中?

【问题讨论】:

    标签: javascript react-native react-hooks infinite-loop


    【解决方案1】:

    我相信您遇到的问题是因为您没有正确分离每个组件的关注点,一旦您每次都必须中继以前的数据,useEffect 可能会很棘手。但是您的问题有两种解决方案:

    利用useState回调函数:

    useState 函数可以与回调而不是值一起使用,如下所示:

        useEffect(() => {
        if (isSelected) {
          setMyState(prevState => [
            ...prevState,
            {
              propOne: 0,
              propTwo: 1,
              id: item.id,
             ...
            },
          ])
        } else {
          setMyState(result)
        }
      }, [isSelected])
    

    组件的最佳结构 + 使用 useState 回调函数

    我可以看到您的方法是您(如您所展示的)似乎正在尝试处理每个项目的isSelected 和同一组件中的myState,这可以完成,但这并不理想。所以我建议创建两个组件,比如说:

    • &lt;List /&gt;:应该处理回调以选择一个项目并渲染它们。

    &lt;List /&gt;:

    function List() {
      const [myState, setMyState] = useState([]);
    
      const isItemSelected = useCallback(
        (itemId) => myState.some((el) => el.id === itemId),
        [myState]
      );
    
      const handleSelectItem = useCallback(
        (itemId) => {
          const isSelected = isItemSelected(itemId);
    
          if (isSelected) {
            setMyState((prevState) => prevState.filter((el) => el.id !== itemId));
          } else {
            setMyState((prevState) => prevState.concat({ id: itemId }));
          }
        },
        [isItemSelected]
      );
    
      return (
        <div>
          <p>{renderTimes ?? 0}</p>
    
          {items.map((item) => (
            <Item
              item={item}
              onSelectItem={handleSelectItem}
              selected={isItemSelected(item.id)}
            />
          ))}
        </div>
      );
    }
    
    • &lt;Item /&gt;:应在内部处理每个项目的 isSelected 字段。

    &lt;Item /&gt;:

    const Item = ({ item, selected = false, onSelectItem }) => {
      const [isSelected, setIsSelected] = useState(false);
    
      useEffect(() => {
        setIsSelected(selected);
      }, [selected]);
    
      return (
        <div>
          <p>
            {item.name} is {isSelected ? "selected" : "not selected"}
          </p>
          <button onClick={() => onClick(item.id)}>
            {isSelected ? "Remove" : "Select"} this item
          </button>
        </div>
      );
    };
    

    这是codesnack,我在其中添加了一个计算渲染的函数,因此您可以检查解决方案的性能。

    【讨论】:

      猜你喜欢
      • 2021-01-20
      • 2022-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-10
      • 2020-09-16
      • 1970-01-01
      相关资源
      最近更新 更多