【问题标题】:I can't find a way out of the infinite loop in React我在 React 中找不到无限循环的方法
【发布时间】:2021-05-17 04:47:53
【问题描述】:

所以我使用了一个useState() 函数、一个数组errors[] 和一个函数setError() 将useState() 函数传递给子元素并从那里调用它:

const [errors, setErrors] = useState([]);
//---------------------------------------------------------------------------------------------------\\
const setError = (courses, day, hour) => {
  if (courses.length > 1) {
    console.log(day, hour);
  }
};

我在这里做的是,我将一些信息传递给 App.js 中的 Schedule 组件,从那里传递给 Hour 组件,然后在小时组件中传递给嵌套在小时组件中的 Day 组件。

<div className="wrapper">
  <h2>Schedule</h2>
  <Schedule setError={setError} courses={pickedCourses} />
</div>
//---------------------------------------------------------------------------------------------------\\
import Hour from "./Hour"

import React from 'react'

const Schedule = ({ courses, setError }) => {
    return (
        <table>
            <tr>
                <th></th>
                <th>Monday</th>
                <th>Tuesday</th>
                <th>Wednesday</th>
                <th>Thursday</th>
                <th>Friday</th>
                <th>Saturday</th>
                <th>Sunday</th>
            </tr>
            <Hour setError={setError} hour={"08:30"} course={courses.filter(i => i.time.some(j => j.includes("08:30")))} />
            <Hour setError={setError} hour={"09:20"} course={courses.filter(i => i.time.some(j => j.includes("09:20")))} />
            <Hour setError={setError} hour={"10:10"} course={courses.filter(i => i.time.some(j => j.includes("10:10")))} />
            <Hour setError={setError} hour={"11:00"} course={courses.filter(i => i.time.some(j => j.includes("11:00")))} />
            <Hour setError={setError} hour={"11:50"} course={courses.filter(i => i.time.some(j => j.includes("11:50")))} />
            <Hour setError={setError} hour={"12:40"} course={courses.filter(i => i.time.some(j => j.includes("12:40")))} />
            <Hour setError={setError} hour={"13:30"} course={courses.filter(i => i.time.some(j => j.includes("13:30")))} />
            <Hour setError={setError} hour={"14:20"} course={courses.filter(i => i.time.some(j => j.includes("14:20")))} />
            <Hour setError={setError} hour={"15:10"} course={courses.filter(i => i.time.some(j => j.includes("15:10")))} />
            <Hour setError={setError} hour={"16:00"} course={courses.filter(i => i.time.some(j => j.includes("16:00")))} />
            <Hour setError={setError} hour={"16:50"} course={courses.filter(i => i.time.some(j => j.includes("16:50")))} />
            <Hour setError={setError} hour={"17:40"} course={courses.filter(i => i.time.some(j => j.includes("17:40")))} />
            <Hour setError={setError} hour={"18:30"} course={courses.filter(i => i.time.some(j => j.includes("18:30")))} />
            <Hour setError={setError} hour={"19:20"} course={courses.filter(i => i.time.some(j => j.includes("19:20")))} />
            <Hour setError={setError} hour={"20:10"} course={courses.filter(i => i.time.some(j => j.includes("20:10")))} />
            <Hour setError={setError} hour={"21:00"} course={courses.filter(i => i.time.some(j => j.includes("21:00")))} />
            <Hour setError={setError} hour={"21:50"} course={courses.filter(i => i.time.some(j => j.includes("21:50")))} />
            <Hour setError={setError} hour={"22:40"} course={courses.filter(i => i.time.some(j => j.includes("22:40")))} />
        </table>
    )
}

export default Schedule

//---------------------------------------------------------------------------------------------------\\
import Day from "./Day"

import React from 'react'

const Hour = ({ hour, course, setError }) => {
    return (
        <tr>
            <th>{hour}</th>
            <Day setError={setError} hour={hour} day={"Pazartesi"} courses={course.filter(i=>i.time.some(j=>j.includes(hour)&&j.includes("Pazartesi")))} />
            <Day setError={setError} hour={hour} day={"Salı"} courses={course.filter(i=>i.time.some(j=>j.includes(hour)&&j.includes("Salı")))} />
            <Day setError={setError} hour={hour} day={"Çarşamba"} courses={course.filter(i=>i.time.some(j=>j.includes(hour)&&j.includes("Çarşamba")))} />
            <Day setError={setError} hour={hour} day={"Perşembe"} courses={course.filter(i=>i.time.some(j=>j.includes(hour)&&j.includes("Perşembe")))} />
            <Day setError={setError} hour={hour} day={"Cuma"} courses={course.filter(i=>i.time.some(j=>j.includes(hour)&&j.includes("Cuma")))} />
            <Day setError={setError} hour={hour} day={"Cumartesi"} courses={course.filter(i=>i.time.some(j=>j.includes(hour)&&j.includes("Cumartesi")))} />
            <Day setError={setError} hour={hour} day={"Pazar"} courses={course.filter(i=>i.time.some(j=>j.includes(hour)&&j.includes("Pazar")))} />
        </tr>
    )
}

export default Hour
//---------------------------------------------------------------------------------------------------\\
import React from 'react'

const Day = ({ hour, day, courses, setError }) => {
    setError(courses, day, hour);
    return (
        <td style={courses.length > 1 ? {backgroundColor: "red"} : null} >{courses.length > 0 ? courses[0].code : null}</td>
    )
}

export default Day

所以我想要做的是,如果 Day 组件的课程参数中传递了 2 个或更多对象,则通过设置 App 组件的状态将一些信息发送到错误数组。但是当我尝试这个时,Day 组件会重新渲染,因为我在该组件中使用了 setState() 函数并且因为它仍然有 2 个或更多对象作为它的课程参数,所以 setState() 再次触发,导致再次重新渲染和无限循环。我将 setError() 函数内部更改为 console.log() 函数,以查看它是否正常运行。它只触发一次并打印出我需要的信息。问题是关于 setState() 函数,它是在它被调用的对象上触发的重新渲染效果。当传递给 Day 对象的课程参数发生变化时,我只需要调用一次 setState()。如何更改我的代码以获得预期的效果?

在我的 Day 组件中使用 useEffect() 后,我已经解决了无限循环的问题,但现在我遇到了一个问题,即我的代码中的 setState() 函数 setErrors() 不会在第一次触发条件如果遇到块。可以看出,当第一个 course.length 超过阈值 1 时,即使我在数组中添加了 1,它也会返回一个空数组,但第二次和之后它正常工作。

我发现这是因为 setState 是异步的,无法跟上 console.log() 的速度。下面的答案就是这个问题的解决方案。

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    您的无限循环发生是因为您在Day 组件的渲染方法中调用setError。它确实会更新应用程序状态,但随后所有子项都将重新渲染,包括Day 组件。然后会发生什么?你猜对了,setError 再次被调用,我们循环,循环,循环。

    Day 组件中执行if (courses.length &gt; 1) 的检查,如下所示:

    useEffect(() => {
        if (courses.length > 1) setError(courses, day, hour);
    }, [courses.length])
    

    由于依赖数组,这只会在课程长度发生变化时运行,包括第一次渲染。所以第一次它会检查长度是否大于 1,设置错误,然后接下来的渲染将不会再次运行。避免了无限循环。

    【讨论】:

    • 这似乎可行,但现在我遇到了另一个问题。当 if first 的条件返回 true 并执行 setError 时,setError 函数内部的 setState 函数不会触发,但是 console.log 等所有其他函数都会正常触发。当条件第二次返回 true 之后,setState 函数似乎起作用了。可以做些什么呢?我将当前输出添加到帖子中以提供帮助。
    • 好的,在我的以下检查中我发现因为 setState 是异步的,console.log() 跟不上它并且没有显示正确的结果。换句话说,您的解决方案有效,非常感谢。
    • 对垃圾邮件感到抱歉,但您的解决方案又遇到了问题。在我的情况下,我同时发送多个 setState 请求,但我发现只有最后一个 setState 请求(我的意思是带有最后一个调用组件的参数的 setState 函数)触发并影响我的状态数组。虽然我应该在数组中一次获得多个输入,但我只获得一个输入,并且始终是最后一个组件的参数。你对这个问题有什么建议吗?
    • 是的!考虑使用在设置器中作为参数传递的最新状态。例如:setSomething((mostCurrent) =&gt; do something with mostCurrent) 如果您这样做,则每次调用都将始终具有最新状态。实现可能是:setError((errors) =&gt; [...errors, newError])
    • 再次感谢。你帮我解决了很多问题。我将 setError 函数传递给 Day 组件,该函数包含 setErrors 函数,它是错误状态数组的 setState 函数。我对此进行了更改,并直接将 setErrors 函数(即 setState 函数)传递给我的组件,并使用您展示的箭头函数更改了先前的状态。这完全解决了我的问题。
    猜你喜欢
    • 2013-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多