You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React项目CI构建失败:useEffect依赖缺失导致编译错误

解决React Hook useEffect依赖缺失导致的构建失败问题

问题背景

功能逻辑:周一至周五的复选框被点击时,将所有复选框状态通过postWorkdayAnswer()接口发送至后端。
本地开发时执行npm start前端运行正常,但执行npm run build触发以下ESLint错误,导致CI流水线构建失败:

src/questions/QuestionComponent.tsx Line 22:8: React Hook useEffect存在缺失依赖:'setWorkdayAnswer'。请添加该依赖或移除依赖数组 react-hooks/exhaustive-deps

尝试过的无效方案

曾尝试将setWorkdayAnswer或setWorkdays添加为该useEffect的依赖项,但均引发日期保存异常问题。

有效解决方案

通过在父组件中使用useCallback优化回调函数,配合子组件调整useEffect依赖数组,解决了依赖缺失问题同时避免了状态异常。

修复后的父组件QuestionList.tsx

import {NavLink} from "react-router-dom";
import {useEffect, useState, useCallback} from "react";
import {getQuestionList, getTimeAnswer} from "../service/apiService";
import QuestionListComponent from "./QuestionComponent";
import {Question, TimeAnswer} from "../service/models";
import "./Questions.css"

export default function QuestionList() {

    const [questionList, setQuestionList] = useState<Array<Question>>([])
    const [errorMessage, setErrorMessage] = useState("")
    const [answers, setAnswers] = useState<Array<TimeAnswer>>([])

    useEffect(() => {
        getQuestionList()
            .then(data => setQuestionList(data))
            .catch(() => setErrorMessage("questionList doesnt load"));
    }, [])

    const onAnswer = useCallback(() => {
        getTimeAnswer()
            .then(data => setAnswers(data))
            .catch(() => setErrorMessage("timeAnswer doesnt load"));
    }, []);

    const questions = questionList.sort((s1, s2) => s1.order - s2.order).map(question => <QuestionListComponent
            key={question.id} question={question} answers={answers} answerCallback={onAnswer}/>)

    return (
        <div className="body">
        <div className="questions">
            <h1 className="questionHeadline"> Questions:</h1>
            {errorMessage && <div>{errorMessage}</div>}
            {questions}

            <br/>
            <br/>

            <NavLink to="/timetable">
                <button className="createButton">create</button>
            </NavLink>
        </div>

        </div>
    )
}

修复后的子组件QuestionComponent.tsx

import {Question, TimeAnswer, TimeUnit, WorkdayAnswer} from "../service/models";
import {useEffect, useState} from "react";
import {getTimeUnitList, postTimeAnswer, postWorkdayAnswer} from "../service/apiService";
import TimeAnswerProperties from "./TimeAnswerProperties";
import "./QuestionComponent.css"
import {convertTimeUnitToMinutes} from "../utilities/Util"

interface QuestionProps {
    question: Question
    answers: Array<TimeAnswer>
    answerCallback: () => void // 刷新页面
}

export default function QuestionListComponent(props: QuestionProps) {
    const [timeUnitList, setTimeUnitList] = useState<Array<TimeUnit>>([])
    const [currentTimeAnswer, setCurrentTimeAnswer] = useState<string>()
    const [workdays, setWorkdays] = useState<boolean[]>([true, true, true, true, true, false, false]);
    const [errorMessage, setErrorMessage] = useState("")

    const question = props.question
    const answerCallback = props.answerCallback

    useEffect(() => {
      const workdayAnswerDbUpdate = () => {
        const workdayAnswer: WorkdayAnswer = {
          questionId: question.id,
          question: question.question,
          monday: workdays[0],
          tuesday: workdays[1],
          wednesday: workdays[2],
          thursday: workdays[3],
          friday: workdays[4],
          saturday: workdays[5],
          sunday: workdays[6],
        };

        postWorkdayAnswer(workdayAnswer)
          .then(() => answerCallback()) // 刷新页面
          .catch(() => {
            console.error("Error posting workday answer:", Error);
            setErrorMessage("error posting answer");
          });
      };

      workdayAnswerDbUpdate();
    }, [answerCallback, question, workdays]);

    useEffect(() => {
        const loadTimeUnitList = async () => {
            try {
                const data = await getTimeUnitList();
                setTimeUnitList(data);
                } catch {
                    setErrorMessage("Failed to load time unit list")
                }
            };

            loadTimeUnitList();

        const currentAnswer = props.answers.find(answer => answer.questionId === props.question.id)
        setCurrentTimeAnswer(currentAnswer ? currentAnswer.time : "00:00");
    }, [props.answers, props.question.id])

    const timeAnswerDbUpdate = (timeInMinutes: number) => {
        const timeAnswer: TimeAnswer = {
            questionId: props.question.id,
            question: props.question.question,
            timeInMinutes: timeInMinutes
        }
        postTimeAnswer(timeAnswer)
            .then(() => props.answerCallback()) // 刷新页面
            .catch(() => {
                console.error("Error posting time answer:", Error);
                setErrorMessage("error posting answer");
                })
    };

    const timeUnitsToChoose = timeUnitList
        .filter(timeUnit => {
            if (!props.question.previousQuestionId) {
                return true;
            } else {
                const previousQuestionAnswer = props.answers.find(answer => answer.questionId === props.question.previousQuestionId)
                if (previousQuestionAnswer) {
                    const currentTimeAnswerInMinutes = convertTimeUnitToMinutes(currentTimeAnswer);
                    return (
                        timeUnit.timeInMinutes! >= previousQuestionAnswer.timeInMinutes) &&
                        timeUnit.timeInMinutes !== currentTimeAnswerInMinutes;
                } else {
                    return true;
                }
            }
        })
        .map(timeUnit => <TimeAnswerProperties key={timeUnit.id} timeUnit={timeUnit}/>)

       const renderWorkdayCheckboxes = () => {
           const days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
           return days.map((day, index) => (
               <span key={index}>
                   <input
                       type="checkbox"
                       id={`check${index}`}
                       checked={workdays[index]}
                       onChange={event => {
                           const newWorkdays = [...workdays];
                           newWorkdays[index] = event.target.checked;
                           setWorkdays(newWorkdays);
                       }}
                   />
                   <label htmlFor={`check${index}`}>{day}</label>
               </span>
           ));
       };

       const QuestionType = () => {
           if (props.question.question === "On which days do you work ?") {
               return (
                   <div>
                       {renderWorkdayCheckboxes()}
                   </div>
               );
           }

           else{
               return(
               <div>
                   <select
                       className="questionAnswer"
                       name={props.question.type}
                       id={props.question.id}
                       onChange={event => timeAnswerDbUpdate(Number(event.target.value))}
                   >
                              value=<TimeAnswerProperties
                              key={currentTimeAnswer}
                              timeUnit={{
                                time: currentTimeAnswer + "",
                                length: 15,
                                 end: "24:00"
                              }}
                              />
                              {timeUnitsToChoose}
                   </select>
               </div>
               );
           }
        };

    return (
        <div className="question">
            <p>{props.question.question}</p>
            {errorMessage && <div>{errorMessage}</div>}
            {QuestionType()}
        </div>
    );
}

内容的提问来源于stack exchange,提问作者Gregor499

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 01:22:02