反应使用效应导致功能运行7次。我正在使用usecallback,但仍有很多次

发布于 2025-02-13 16:09:48 字数 4765 浏览 0 评论 0原文

带有Console.log(“运行”)的UpdateAtDedState函数在页面刷新/初始渲染上运行7次。

我只希望在AddItems状态更新时updateDedState函数一次运行。

我只有当实际的additems状态发生了变化时,使用效率要运行。我在做什么错?

export const DropdownMultiSelect = ({
  data,
  placeholder,
  updateState,
}: IProps) => {
  const [searchTerm, setSearchTerm] = useState<string>("");
  const [filteredData, setFilteredData] = useState<IData[]>(data);
  const [addedItems, setAddedItems] = useState<IData[]>([]);
  const [placeholderValue, setPlaceholderValue] = useState<string>("");
  const [inputActive, setInputActive] = useState<boolean>(false);

  const onFocus = () => setInputActive(true);
  const onBlur = () => {
    setInputActive(false);
  };

  const updateAddedState = useCallback(() => {
    console.log("running");
    
    updateState(addedItems);
  }, [updateState, addedItems]);

  const handleFilter = (e: React.ChangeEvent<HTMLInputElement>) => {
    setSearchTerm(e.target.value);
  };

  const handleFilterData = useCallback(
    (searchTerm: string) => {
      let newFilter = data.filter((value) => {
        return value.name.toLowerCase().includes(searchTerm.toLowerCase());
      });

      for (let i = 0; i < addedItems.length; i++) {
        for (let j = 0; j < newFilter.length; j++) {
          if (addedItems[i].id === newFilter[j].id) {
            newFilter.splice(j, 1);
          }
        }
      }

      setFilteredData(newFilter);
    },
    [addedItems, data]
  );

  const addItem = (value: IData) => {
    setAddedItems([...addedItems, value]);
    setSearchTerm("");
    handleFilterData("");
    setInputActive(false);
  };

  const removeItem = (value: IData, e: React.MouseEvent) => {
    e.preventDefault();
    let newArray: IData[] = [];

    for (let i = 0; i < addedItems.length; i++) {
      newArray.push(addedItems[i]);
    }

    for (let i = 0; i < newArray.length; i++) {
      if (value.id === newArray[i].id) {
        newArray.splice(i, 1);
      }
    }
    setAddedItems(newArray);
    setInputActive(true);
  };

  useEffect(() => {
    if (addedItems.length === 1) {
      setPlaceholderValue(`${addedItems.length} vald`);
    } else if (addedItems.length > 1) {
      setPlaceholderValue(`${addedItems.length} valda`);
    } else {
      setPlaceholderValue(placeholder);
    }
  }, [addedItems, placeholderValue, placeholder]);

  useEffect(() => {
    handleFilterData(searchTerm);
  }, [searchTerm, addedItems, handleFilterData]);

  useEffect(() => {
    let isMounted = true;
    if (isMounted) {
      if (addedItems) {
        updateAddedState();
      }
    }

    return () => {
      isMounted = false;
    };
  }, [updateAddedState, addedItems]);

  return (
    <div id="dropdownMulti">
      <section className="inputSection">
        <input
          type="text"
          placeholder={placeholderValue}
          className="inputSection__input"
          onChange={handleFilter}
          value={searchTerm}
          onFocus={onFocus}
          onBlur={onBlur}
        />
        <div className="inputSection__icon-container">
          {inputActive ? (
            <AiOutlineUpCircle
              onClick={() => setInputActive(false)}
              className="inputSection__icon-container--up"
            />
          ) : (
            <AiOutlineDownCircle className="inputSection__icon-container--down" />
          )}
        </div>
      </section>
      <section className="addedItems-section">
        {inputActive &&
          addedItems.map((addedItem) => {
            return (
              <div className="addedItem" key={addedItem.id}>
                <p className="addedItem__item">{addedItem?.name}</p>
                <button
                  data-testid="remove-btn"
                  className="addedItem__button"
                  onMouseDown={(e: React.MouseEvent) =>
                    removeItem(addedItem, e)
                  }
                >
                  <AiOutlineCloseCircle />
                </button>
              </div>
            );
          })}
      </section>
      {inputActive && (
        <ul className="dataResult">
          {filteredData.slice(0, 10).map((value) => {
            return (
              <li
                className="dataResult__item"
                key={value.id}
                tabIndex={0}
                onMouseDown={() => addItem(value)}
              >
                {value.name}
              </li>
            );
          })}
        </ul>
      )}
    </div>
  );
};


关于如何削减其运行次数的任何提示?

The updateAddedState function with the console.log("running") is running 7 times on a page refresh/initial render.

I only want the updateAddedState function to run once when the addedItems state updates.

I only what the useEffect to run when the actual addedItems state has changed. What am I doing wrong??

export const DropdownMultiSelect = ({
  data,
  placeholder,
  updateState,
}: IProps) => {
  const [searchTerm, setSearchTerm] = useState<string>("");
  const [filteredData, setFilteredData] = useState<IData[]>(data);
  const [addedItems, setAddedItems] = useState<IData[]>([]);
  const [placeholderValue, setPlaceholderValue] = useState<string>("");
  const [inputActive, setInputActive] = useState<boolean>(false);

  const onFocus = () => setInputActive(true);
  const onBlur = () => {
    setInputActive(false);
  };

  const updateAddedState = useCallback(() => {
    console.log("running");
    
    updateState(addedItems);
  }, [updateState, addedItems]);

  const handleFilter = (e: React.ChangeEvent<HTMLInputElement>) => {
    setSearchTerm(e.target.value);
  };

  const handleFilterData = useCallback(
    (searchTerm: string) => {
      let newFilter = data.filter((value) => {
        return value.name.toLowerCase().includes(searchTerm.toLowerCase());
      });

      for (let i = 0; i < addedItems.length; i++) {
        for (let j = 0; j < newFilter.length; j++) {
          if (addedItems[i].id === newFilter[j].id) {
            newFilter.splice(j, 1);
          }
        }
      }

      setFilteredData(newFilter);
    },
    [addedItems, data]
  );

  const addItem = (value: IData) => {
    setAddedItems([...addedItems, value]);
    setSearchTerm("");
    handleFilterData("");
    setInputActive(false);
  };

  const removeItem = (value: IData, e: React.MouseEvent) => {
    e.preventDefault();
    let newArray: IData[] = [];

    for (let i = 0; i < addedItems.length; i++) {
      newArray.push(addedItems[i]);
    }

    for (let i = 0; i < newArray.length; i++) {
      if (value.id === newArray[i].id) {
        newArray.splice(i, 1);
      }
    }
    setAddedItems(newArray);
    setInputActive(true);
  };

  useEffect(() => {
    if (addedItems.length === 1) {
      setPlaceholderValue(`${addedItems.length} vald`);
    } else if (addedItems.length > 1) {
      setPlaceholderValue(`${addedItems.length} valda`);
    } else {
      setPlaceholderValue(placeholder);
    }
  }, [addedItems, placeholderValue, placeholder]);

  useEffect(() => {
    handleFilterData(searchTerm);
  }, [searchTerm, addedItems, handleFilterData]);

  useEffect(() => {
    let isMounted = true;
    if (isMounted) {
      if (addedItems) {
        updateAddedState();
      }
    }

    return () => {
      isMounted = false;
    };
  }, [updateAddedState, addedItems]);

  return (
    <div id="dropdownMulti">
      <section className="inputSection">
        <input
          type="text"
          placeholder={placeholderValue}
          className="inputSection__input"
          onChange={handleFilter}
          value={searchTerm}
          onFocus={onFocus}
          onBlur={onBlur}
        />
        <div className="inputSection__icon-container">
          {inputActive ? (
            <AiOutlineUpCircle
              onClick={() => setInputActive(false)}
              className="inputSection__icon-container--up"
            />
          ) : (
            <AiOutlineDownCircle className="inputSection__icon-container--down" />
          )}
        </div>
      </section>
      <section className="addedItems-section">
        {inputActive &&
          addedItems.map((addedItem) => {
            return (
              <div className="addedItem" key={addedItem.id}>
                <p className="addedItem__item">{addedItem?.name}</p>
                <button
                  data-testid="remove-btn"
                  className="addedItem__button"
                  onMouseDown={(e: React.MouseEvent) =>
                    removeItem(addedItem, e)
                  }
                >
                  <AiOutlineCloseCircle />
                </button>
              </div>
            );
          })}
      </section>
      {inputActive && (
        <ul className="dataResult">
          {filteredData.slice(0, 10).map((value) => {
            return (
              <li
                className="dataResult__item"
                key={value.id}
                tabIndex={0}
                onMouseDown={() => addItem(value)}
              >
                {value.name}
              </li>
            );
          })}
        </ul>
      )}
    </div>
  );
};


Any tips on how to cut the number of times it runs?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

濫情▎り 2025-02-20 16:09:48

尝试删除React严格模式,它使组件仅在开发中呈现两次,而不是在生产中。如果是这种情况,请重新打开。

Try to remove React Strict Mode, it makes components render twice only in development, not in production. Put back on if it's the case.

草莓味的萝莉 2025-02-20 16:09:48

尝试从usecallback函数的依赖项数组中删除更新函数。

 const updateAddedState = useCallback(() => {
    console.log("running");
    
    updateState(addedItems);
  }, [addedItems]);

如果仍无法正常工作,则定义与定义该函数的Usecallback Hook随附的Props的UpdateState函数。

Try removing updateState function from the dependency array of the useCallback function.

 const updateAddedState = useCallback(() => {
    console.log("running");
    
    updateState(addedItems);
  }, [addedItems]);

If it's still not working define the updateState function which comes with the props with the useCallback hook where the function is defined.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文