I'm using recoiljs as my state manager for my react project, and one of my components doesn't call it's useEffect when a recoil atom changes from another file. Here is my main component that reads from an atom.
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>
</>
)
}
Here is my atom file
import {atom} from 'recoil'
const DeadlineList = atom({
key: "deadlinelist",
default: []
});
export default DeadlineList;
and here is the form that I'm submitting in
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>
)
}
If you want to just see file for file the github is here The main component is src/components/MainDeadline.jsx , src/atoms/deadlinelist , src/components/InputForm.jsx
My main problem is when the user inputs something in the form, it's supposed to update the state, but the main component doesn't update.
Please tell me if I can improve my code in any way this is my first react project.
When dealing with arrays in state hooks, you need to clone the array as you do the set function.
Also, instead of this: let [deadlinelist, setDeadlineList] = useRecoilValue(DeadlineList);
I would do this: const [deadlinelist, setDeadlineList] = useRecoilState(DeadlineList);