首页 > 解决方案 > React useEffect hook在recoil atom更新后不调用

问题描述

我使用 recoiljs 作为我的反应项目的状态管理器,当一个反冲原子从另一个文件更改时,我的一个组件不会将其称为 useEffect。这是我从原子读取的主要组件。

import React, {useState, useEffect} from 'react'
import '../css/MeadDeadline.css'
import {getNearestDate} from '../chromeAPI/retrieveDeadlineJSON'

import DeadlineList from '../atoms/deadlinelist'
import {useRecoilValue} from 'recoil'

export default function MainDeadline() {
    // get the date and the stuff from chrome storage
    const [school, setSchool] = useState("");
    const [date, setDate] = useState("");
    let [deadlinelist, setDeadlineList] = useRecoilValue(DeadlineList);

    useEffect(() => {
        const nearest = getNearestDate(deadlinelist);
        const len = nearest.length;

        if (len === 0){
            setSchool("No schools registered");
            setDate("");

        } else if (len === 1){
            setSchool(nearest[0].school);
            setDate(nearest[0].date);
            
        } else {
            // we need to render a lot of stuff
            console.log("error");
        }

    }, [deadlinelist]);

    return (
        <>
            <div className="MainDeadline">
                <div className='school'>{school}</div>
                <div classNmae='date'>{date}</div>
            </div>
        </>
    )
}

这是我的原子文件

import {atom} from 'recoil'

const DeadlineList = atom({
    key: "deadlinelist",
    default: []
}); 
export default DeadlineList;

这是我提交的表格

import React, {useState} from 'react'
import '../css/InputForm.css'
import checkList from '../utils/checkList'
import checkDate from '../utils/checkDate'
import {storeNewDeadline} from '../chromeAPI/storeNewDeadline'

import {useRecoilState} from 'recoil'
import DeadlineList from '../atoms/deadlinelist'
import SchoolList from '../atoms/schoollist'

export default function InputForm () {
    const [inputschool, setInputSchool] = useState('');
    const [inputdate, setInputDate] = useState('');
    const [invalidschool, setInvalidSchool] = useState(false);
    const [invaliddate, setInvalidDate] = useState(false);
    const [badschool, setBadSchool] = useState('');
    const [baddate, setBadDate] = useState('');

    const [schoollist, setSchoolList] = useRecoilState(SchoolList);
    const [deadlinelist, setDeadlineList] = useRecoilState(DeadlineList);

    const validateForm = () => {
        // check to make sure its not in the list
        const valschool = checkList(schoollist, inputschool);
        if (!valschool){
            setInvalidSchool(true);
            setBadSchool(inputschool);
        } else {
            setInvalidSchool(false);
            setBadSchool("");
        }
        // check to make sure the date hasnt been reached yet
        const valdate = checkDate(inputdate);
        if (!valdate){ // add MSIN1DAY becauase the day value is 0 indexed so conflicts with Date() and date input
            setInvalidDate(true);
            setBadDate(inputdate);
        }
        else {
            setInvalidDate(false);
            setBadDate("");
        }

        return !invalidschool && !invaliddate; // want both to be valid
    }

    const handleSubmit = async(event) => {
        event.preventDefault();
        
        // validate the form
        if (validateForm()){
            storeNewDeadline(inputschool, inputdate);

            // change schoollist state
            let slist = schoollist;
            slist.push(inputschool);
            setSchoolList(slist);

            // change deadlinelist state
            let dlist = deadlinelist;
            dlist.push({
                "school": inputschool,
                "date": inputdate
            });
            setDeadlineList(dlist);

            console.log(deadlinelist, schoollist);
        }
    }

    const handleChange = (event, fieldname) => {
        switch (fieldname) {
            case "inputschool":
                setInputSchool(event.target.value);
                break;
            
            case "inputdate":
                setInputDate(event.target.value);
                break;
            
            default:
                break;
        }
    }

    return (
        <form className='InputForm' onSubmit={handleSubmit}>
            <h3>Enter New School</h3>

            <div id='inputname' className='Inputer'>
                <p>School Name</p>
                <input 
                    type='text'
                    onChange={e => {handleChange(e, 'inputschool')}}
                    value={inputschool}
                    required 
                />
                {invalidschool ? <p>{badschool} is already registered</p> : null}
            </div>

            <div id='inputdate' className='Inputer'>
                <p>Deadline Date</p>
                <input
                    type='date'
                    onChange={e => {handleChange(e, 'inputdate')}}
                    value={inputdate}
                    required
                />
                {invaliddate ? <p>{baddate} is invalid</p> : null}
            </div>

            <div id='inputsubmit' className='Inputer'>
                <p>Submit</p>
                <input type='submit' required></input>
            </div>
            
        </form>
    )
}

如果您只想查看文件,github 在这里 主要组件是 src/components/MainDeadline.jsx , src/atoms/deadlinelist , src/components/InputForm.jsx

我的主要问题是当用户在表单中输入内容时,它应该更新状态,但主要组件没有更新。

请告诉我是否可以以任何方式改进我的代码这是我的第一个反应项目。

标签: javascriptreactjsjsxuse-effectrecoiljs

解决方案


在状态挂钩中处理数组时,您需要在执行 set 函数时克隆数组。

此外,而不是这个:让 [deadlinelist, setDeadlineList] = useRecoilValue(DeadlineList);

我会这样做: const [deadlinelist, setDeadlineList] = useRecoilState(DeadlineList);


推荐阅读