繁体   English   中英

useCallback 中的生成器 function 在反应中返回相同的值,如何解决这个问题?

[英]Generator function inside useCallback is returning same values in react, How to solve this?

我正在 React 中创建待办应用程序,对于我正在使用生成器 function 的任务 ID。但是这个生成器 function 每次都给出值 0 而不是递增值。我认为问题的原因是 useCallback() 钩子,但我是不确定解决方案是什么。如何解决这个问题?我在这里提供代码:

import DateAndDay, { date } from "../DateAndDay/DateAndDay";
import TaskList, { TaskProps } from "../TaskList/TaskList";
import "./ToDo.css";
import Input from "../Input/Input";
import { ChangeEvent, useCallback, useEffect, useState } from "react";

function ToDo() {
  const [inputShow, setInputShow] = useState(false);
  const [valid, setValid] = useState(false);
  const [enteredTask, setEnteredTask] = useState("");
  const [touched, setTouched] = useState(false);
  const [tasks, setTasks] = useState<TaskProps[]>(() => {
    let list = localStorage.getItem("tasks");
    let newdate = String(date);
    const setdate = localStorage.getItem("setdate");
    if (newdate !== setdate) {
      localStorage.removeItem("tasks");
    }
    if (list) {
      return JSON.parse(list);
    } else {
      return [];
    }
  });

  const activeHandler = (id: number) => {
    const index = tasks.findIndex((task) => task.id === id);
    const updatedTasks = [...tasks];
    updatedTasks[index].complete = !updatedTasks[index].complete;
    setTasks(updatedTasks);
  };

  const clickHandler = () => {
    setInputShow((prev) => !prev);
  };

  const input = inputShow && (
    <Input
      checkValidity={checkValidity}
      enteredTask={enteredTask}
      valid={valid}
      touched={touched}
    />
  );

  const btn = !inputShow && (
    <button className="add-btn" onClick={clickHandler}>
      +
    </button>
  );

  function checkValidity(e: ChangeEvent<HTMLInputElement>) {
    setEnteredTask(e.target.value);
  }

  function* idGenerator() {
    let i = 0;
    while (true) {
      yield i++;
    }
  }
  let id = idGenerator();

  const submitHandler = useCallback(
    (event: KeyboardEvent) => {
      event.preventDefault();
      setTouched(true);
      if (enteredTask === "") {
        setValid(false);
      } else {
        setValid(true);
        const newtitle = enteredTask;
        const newComplete = false;
        const obj = {
          id: Number(id.next().value),
          title: newtitle,
          complete: newComplete,
        };
        setTasks([...tasks, obj]);
        localStorage.setItem("setdate", date.toString());
        setEnteredTask("");
      }
    },
    [enteredTask, tasks, id]
  );

  useEffect(() => {
    const handleKey = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setInputShow(false);
      }
      if (event.key === "Enter") {
        submitHandler(event);
      }
    };

    document.addEventListener("keydown", handleKey);

    return () => {
      document.removeEventListener("keydown", handleKey);
    };
  }, [submitHandler]);

  useEffect(() => {
    localStorage.setItem("tasks", JSON.stringify(tasks));
  }, [tasks]);

  return (
    <div className="to-do">
      <DateAndDay />
      <TaskList tasks={tasks} activeHandler={activeHandler} />
      {input}
      {btn}
    </div>
  );
}
export default ToDo;

useCallBack()的用于记忆function发送给它的结果。 这个结果永远不会改变,直到依赖数组的任何变量/函数改变它的值。 因此,请检查传递的依赖项是否正确,或者它们是否在您的代码中发生了变化(或提供此文件的所有代码)。 我的猜测之一是将 Valid state 作为依赖项添加到数组

这是因为您在idGenerator之外调用了 idGenerator,所以只有在重新呈现组件时才会生成它,在您的情况下……只有一次。

在 useCallback 中调用它,并在每次触发事件时调用它:

// wrap this on a useCallback so it gets memoized
const idGenerator = useCallback(() => {
    let i = 0;
    while (true) {
      yield i++;
    }
  }, []);

  const submitHandler = useCallback(
    (event: KeyboardEvent) => {
      event.preventDefault();
      
      let id = idGenerator();
      // ... rest of logic
    },
    [enteredTask, tasks, idGenerator]
  );

如果您在事件处理程序之外使用生成的id ,请将 ID 存储在 state 中,如下所示:


const idGenerator = useCallback(() => {
    let i = 0;
    while (true) {
      yield i++;
    }
  }, []);

const [id, setId] = useState(idGenerator());

  const submitHandler = useCallback(
    (event: KeyboardEvent) => {
      event.preventDefault();
      
      let newId = idGenerator();
      setId(newId)
      // ... rest of logic
    },
    [enteredTask, tasks, id, idGenerator]
  );

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM