简体   繁体   English

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

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

I am creating to-do app in react and for the id of task i am using generator function. But This generator function is giving value 0 everytime and not incrementing the value.I think the reason for issue is useCallback() hook but i am not sure what can be the solution.How to solve the issue?Here i am providing the code:我正在 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()'s is used to memorize the result of function sent to it. useCallBack()的用于记忆function发送给它的结果。 This result will never change until any variable/function of dependency array changes it's value.这个结果永远不会改变,直到依赖数组的任何变量/函数改变它的值。 So, please check if the dependencies passed are correct or if they are changing in your code or not ( or provide all the code of this file).因此,请检查传递的依赖项是否正确,或者它们是否在您的代码中发生了变化(或提供此文件的所有代码)。 One of my guess is to add the Valid state as dependency to the array我的猜测之一是将 Valid state 作为依赖项添加到数组

It's because you are calling the idGenerator outside of the useCallback, so it is only generated if the Component is re-rendered, in your case... only once.这是因为您在idGenerator之外调用了 idGenerator,所以只有在重新呈现组件时才会生成它,在您的情况下……只有一次。

Transfer it inside useCallback and call it everytime the event is triggered:在 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]
  );

If you're using the generated id outside the event handler, store the id inside a state like so:如果您在事件处理程序之外使用生成的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