I’m running into an error that I could use some help on
Basically, I have a react app that is executing an HTTP call, receiving an array of data, and saving that into a state variable called ‘tasks’. Each object in that array has a key called ‘completed’. I also have a checkbox on the page called ‘Show All’ that toggles another state variable called showAll. The idea is by default all tasks should be shown however if a user toggles this checkbox, only the incomplete tasks (completed==false) should be shown. I can get all tasks to display but can’t get the conditional render to work based on the checkbox click
Here’s how I’m implementing this. I have the HTTP call executed on the page load using a useEffect hook and available to be called as a function from other change handlers (edits etc.)
Before I call the main return function in a functional component, I’m executing a conditional to check the status of ’ShowAll’ and filter the array if it's false. This is resulting in too many re-render errors. Any suggestions on how to fix it?
See simplified Code Below
const MainPage = () => {
const [tasks, setTasks] = useState([]); //tasks
const [showAll, setShowAll] = useState(true); //this is state for the checkbox (show all or just incomplete)
useEffect( ()=> {
axios.get('api/tasks/')
.then( response => { //this is the chained API call
setTasks(response.data.tasks);
})
.catch(err => {
console.log('error');
})
}, []);
const fetchItems = (cat_id) => {
axios.get('/api/tasks/')
.then( response => {
setTasks(response.data.tasks);
})
.catch(err => {
console.log('error');
})
};
//change the checkbox state
const handleCheckboxChange = (e) => {
setShowAll(!showAll)
console.log('Checkbox: ', showAll)
};
//this part updates the tasks to be filtered down to just the incomplete ones based on the checkbox value
if (showAll === false) {
setTasks(tasks.filter(v => v['completed']===false)); //only show incomplete tasks
}
return (
<div>
<label className="checkb">
<input
name="show_all"
id="show_all"
type="checkbox"
checked={showAll}
onChange={handleCheckboxChange}
/> Show all
</label>
<br/>
{ tasks && tasks.map((task, index) => {
return (
<div key={index} className="task-wrapper flex-wrapper">
<div >
{ task.completed === false ? (
<span> {index 1}. {task.task_description} </span> ) :
(<strike> {index 1}. {task.task_description} </strike>) }
</div>
<div>
<button
onClick={()=> modalClick(task)}
className="btn btn-sm btn-outline-warning">Edit</button>
<span> </span>
</div>
</div>
)
})}
</div>
);
};
export default MainPage;
Thanks
CodePudding user response:
Two things to fix:
Use the checked property on event.target
to update the state:
const handleCheckboxChange = ({target: { checked }}) => {
setShowAll(checked)
};
Filter as you want but don't update the state right before returning the JSX as that would trigger a rerender and start an infinite loop:
let filteredTasks = tasks;
if (!showAll) {
filteredTasks = tasks?.filter(v => !v.completed));
}
and in the JSX:
{ tasks && tasks.map
should be {filteredTasks?.map(...
CodePudding user response:
use e.target.value and useEffect :
//change the checkbox state
const handleCheckboxChange = (e) => {
setShowAll(e.target.checked)
console.log('Checkbox: ', showAll)
if (!e.target.checked) {
let list =tasks.filter(v => v.completed===false);
setTasks(list ); //only show incomplete tasks
}
};
or
//change the checkbox state
const handleCheckboxChange = (e) => {
setShowAll(e.target.checked)
console.log('Checkbox: ', showAll)
};
useEffect(()=>{
if (showAll === false) {
let list =tasks.filter(v => v.completed===false);
setTasks(list ); //only show incomplete tasks
}
},[showAll])