Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/425.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 反应:将行为与useEffect和/或useState挂钩混淆_Javascript_Reactjs - Fatal编程技术网

Javascript 反应:将行为与useEffect和/或useState挂钩混淆

Javascript 反应:将行为与useEffect和/或useState挂钩混淆,javascript,reactjs,Javascript,Reactjs,这里是诺布。我正在尝试制作一个简单的练习应用程序来帮助我的反应学习,我得到了很多奇怪的行为。这是一个有多个待办事项列表可供选择的待办事项应用程序。我想要的行为是一个Todo列表列表,您可以在其中选择一个和Todo项(如wunderlist/msft Todo)。选择一个不同的列表,它的todo items show等等。此时,它使用静态json,其中每个项都有一个子数组 useEffect-我正试图使用它来加载数据。它不断抱怨缺少依赖项。当我添加它们时,它也会对此抱怨。如果我对第二个参数使用an

这里是诺布。我正在尝试制作一个简单的练习应用程序来帮助我的反应学习,我得到了很多奇怪的行为。这是一个有多个待办事项列表可供选择的待办事项应用程序。我想要的行为是一个Todo列表列表,您可以在其中选择一个和Todo项(如wunderlist/msft Todo)。选择一个不同的列表,它的todo items show等等。此时,它使用静态json,其中每个项都有一个子数组

useEffect-我正试图使用它来加载数据。它不断抱怨缺少依赖项。当我添加它们时,它也会对此抱怨。如果我对第二个参数使用and empty array,它会抱怨,并且似乎会多次触发

useState-我正在使用它来存储数据。它被初始化为一个空数组。但render是在useEffect之前触发的,它表示我的数据未定义,所以我的第二个列表从不渲染

我在代码中有几个console.log,它们都会触发多次

我敢肯定这只是noob的错误,但在这一点上我很难堪。这是我的密码:

data/Todo.js

const TodoData=[
{
Id:1,
标题:“食品杂货”,
托多利斯特:[
{
Id:1,
标题:“苹果”
},
{
Id:2,
标题:“橙子”
},
{
Id:3,
标题:“香蕉”
}
]
},
{
Id:2,
标题:“日常任务”,
托多利斯特:[
{
Id:11,
标题:“清洁厨房”
},
{
Id:12,
标题:“饲养宠物”
},
{
Id:13,
标题:“做事”
}
]
},
{
Id:3,
标题:“五金店”,
托多利斯特:[]
},
{
Id:4,
标题:“好市多”,
托多利斯特:[
{
Id:21,
标题:“尿布”
},
{
身份证号码:22,
标题:“猫粮”
},
{
Id:23,
标题:“苹果”
},
{
Id:24,
标题:“香蕉”
}
]
},
{
Id:5,
标题:“工作”,
托多利斯特:[
{
Id:34,
标题:“TPS报告”
}
]
}
];

将默认值导出到ODataQ:useffect-我正试图使用它来加载数据。它不断抱怨缺少依赖项

A:您可以通过
eslint(react hooks/deps)忽略它
,无需担心


Q:useState-我用它来存储数据。它被初始化为一个空数组。但render是在useEffect之前触发的,它表示我的数据未定义,所以我的第二个列表从不渲染

A:一定要阅读代码中的注释,希望能消除您的疑虑

// you are intializing `todoDetails` with array, when there will be object
// hence the error while mapping inside the html/jsx
// const [todoDetails, setTodoDetails] = useState([]);

// init with `null`, why?
const [todoDetails, setTodoDetails] = useState(null);

// so that you can do something like this
{
  todoDetails && (   // <---------- HERE
    <ul className="list-group">
      <h2>{todoDetails.Title} List</h2>

      {console.log(todoDetails.TodoList)}

      {/* this fails miserably */}
      {todoDetails.TodoList.map(details => (
        <li className="list-group-item" key={details.Id}>
          {details.Title}
        </li>
      ))}
    </ul>
  )
}
//您正在使用数组初始化'todoDetails',此时将出现对象
//因此,在html/jsx内部映射时会出现错误
//const[todoDetails,settodetails]=useState([]);
//init带有'null',为什么?
const[todoDetails,settodetails]=useState(null);
//这样你就可以做这样的事情
{
todoDetails&(//(
  • {details.Title}
  • ))} ) }

    Q:现在您将获得多个
    控制台.log

    A:这背后的原因是

    React可以在提交之前多次调用呈现阶段生命周期,也可以在根本不提交的情况下调用它们(由于错误或更高优先级的中断)

    我已经从演示中的
    index.js
    中删除了它,所以您可以看到它的差异


    工作演示:


    您必须将getToData的逻辑放入
    useffect
    钩子中

    useEffect(() => {
        const getTodoData = () => {
          setTodoData(TodoData);
          console.log("getting todo data");
          getTodoDetails(1);
        };
    
        if (todoData.length === 0) {
          getTodoData();
        }
      }, [todoData.length]);
    
    以及在渲染中

    {
    //检查todoDetails是否有TodoList
    todoDetails.TodoList&&
    todoDetails.TodoList.map((详细信息)=>(
    
  • {details.Title}
  • )); }

    以下是更新后的

    您评论并说失败的代码是由于
    todoDetails造成的。TodoList
    在第一次呈现组件时可能未定义。为了避免这种情况,可以使用一个项目初始化
    todoDetails
    ,或者在调用
    .map
    之前检查
    todoDetails.TodoList
    是否已定义

    {todoDetails.TodoList ? todoDetails.TodoList.map(details => (
      <li className="list-group-item" key={details.Id}>
        {details.Title}
      </li>
    )) : null}
    
    不要太担心
    eslint(react hooks/deps)
    错误。您需要了解
    useffect
    的第二个参数的含义。在代码中,您将
    todoData
    传递给
    useffect

      useEffect(() => {
        if (todoData.length === 0) {
          getTodoData();
        }
      }, [todoData]);
    
    这意味着,每当
    todoData
    更改时,
    useffect
    将运行,其行为类似于
    componentdiddupdate
    。如果您只传递一个空数组,这意味着您的useEffect没有依赖项,它将只执行一次,其行为类似于
    componentDidMount
    。所以,你在这里做的很好

    除此之外,我还可以给您一些关于代码的提示:

    关于
    handleClick
    函数,您可以删除它,然后简单地调用
    getTodoDetails(id)
    传递id,而不是将其添加到
    数据id
    并在以后获取,方法如下:

    <button
      key={todos.Id}
      className="btn list-group-item d-flex justify-content-between align-items-center"
      onClick={() => getTodoDetails(todos.Id)} // <---- change is in here
    >
      {todos.Title}
      <span className="badge badge-primary badge-pill">
        {todos.TodoList.length}
      </span>
    </button>
    
    您正在将您的
    作为
    对象进行详细建模
    ,并将其初始化为
    数组
    。如果
    todetails
    始终只有一个todo,请将其初始化为对象,这样可以防止从数组访问
    todetails.Title
    。渲染后将始终执行
    useffect

    const [todoDetails, setTodoDetails] = useState({});
    

    useffect
    钩子有时会很奇怪。要修复它,只需直接传入
    getToData
    函数,如下所示:

    const gettodata=()=>{
    setTodoData(TodoData);
    log(“获取待办事项数据”);
    getTodoDetails(1);
    };
    useffect(gettodata,[]);
    

    const getTodoDetails = id => { const result = TodoData.find(x => x.Id === id); console.log(result); setTodoDetails(result); };

    const [todoDetails, setTodoDetails] = useState({});
    
    import React, { useEffect, useState } from "react";
    import TodoData from "./data/Todo.js";
    
    function App() {
      const [todoData, setTodoData] = useState([]);
      const [todoDetails, setTodoDetails] = useState([]);
    
      const getTodoData = () => {
        setTodoData(TodoData);
        console.log("getting todo data");
        getTodoDetails(1);
      };
    
      useEffect(getTodoData, []);
    
      const getTodoDetails = id => {
        const result = TodoData.filter(x => x.Id === id);
        console.log(result[0]);
        setTodoDetails(result[0]);
      };
    
      const handleClick = e => {
        const selectedId = Number(e.target.getAttribute("data-id"));
        getTodoDetails(selectedId);
      };
    
      return (
        <div className="App">
          <div className="container-fluid">
            <div className="row">
              <div className="list-group col-md-4 offset-md-1">
                {todoData.map(todos => (
                  <button
                    key={todos.Id}
                    data-id={todos.Id}
                    className="btn list-group-item d-flex justify-content-between align-items-center"
                    onClick={handleClick}
                  >
                    {todos.Title}
                    <span className="badge badge-primary badge-pill">
                      {todos.TodoList.length}
                    </span>
                  </button>
                ))}
              </div>
              <div className="col-md-6">
                <ul className="list-group">
                  <h2>{todoDetails.Title} List</h2>
    
                  {console.log(todoDetails.TodoList)}
    
                  {todoDetails.TodoList.map(details => (
                    <li className="list-group-item" key={details.Id}>
                      {details.Title}
                    </li>
                  ))}
                </ul>
              </div>
            </div>
           </div>
        </div>
       );
    }
    export default App;