Хук React useEffect не вызывается после обновления атома отдачи

Я использую 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 / atom / deadlinelist, src / components / InputForm.jsx

Моя основная проблема заключается в том, что когда пользователь вводит что-то в форму, это должно обновлять состояние, но основной компонент не обновляется.

Скажите, могу ли я как-нибудь улучшить свой код? Это мой первый проект реагирования.


person feverdream    schedule 11.01.2021    source источник
comment
Одна вещь, которая выделяется для меня, это то, что вы напрямую изменяете состояние отдачи следующим образом: let dlist = deadlinglines; dlist.push({/*...*/}); dlist - это ссылка на фактическое состояние. Вместо этого вам следует клонировать существующий список. let dlist = [...deadlinelist, {school: school, date: date}]   -  person HaveSpacesuit    schedule 15.01.2021
comment
@HaveSpacesuit, спасибо, что поймали это!   -  person feverdream    schedule 15.01.2021


Ответы (1)


При работе с массивами в хуках состояний вам необходимо клонировать массив, как вы выполняете функцию set.

Также вместо этого: let [deadlinelist, setDeadlineList] = useRecoilValue (DeadlineList);

Я бы сделал следующее: const [deadlinelist, setDeadlineList] = useRecoilState (DeadlineList);

person dmalechek    schedule 20.01.2021
comment
Спасибо! Я забыл закрыть его после того, как наткнулся на решение, но спасибо за объяснение почему работает useRecoilState, а не useRecoilValue - person feverdream; 20.01.2021