React noob here. I'm trying to make a simple practice app to help with my React learning and I'm getting a lot of odd behavior. It's a Todo app with multiple todo lists to choose from. The behavior I'm going for is a list of Todo lists, where you select one and the todo items for that (like wunderlist/msft todo). Select a different list and it's todo items show, etc. At this point it's using static json where each item has a child array.
useEffect - I’m trying to use this to load the data. It keeps complaining about missing dependencies. When I add them it complains about that too. It complains if I use and empty array for the second parameter and seems to fire multiple times.
useState - I'm using this to store the data. It's initialized to an empty array. But render is firing before useEffect and it's saying my data is undefined so my second list never renders.
I have several console.logs in the code and they're all firing multiple times.
I'm sure it's just noob mistakes but I'm pretty stumped at this point. Here's my code:
data/Todo.js
const TodoData = [
{
Id: 1,
Title: "Groceries",
TodoList: [
{
Id: 1,
Title: "Apples"
},
{
Id: 2,
Title: "Oranges"
},
{
Id: 3,
Title: "Bananas"
}
]
},
{
Id: 2,
Title: "Daily Tasks",
TodoList: [
{
Id: 11,
Title: "Clean Kitchen"
},
{
Id: 12,
Title: "Feed Pets"
},
{
Id: 13,
Title: "Do Stuff"
}
]
},
{
Id: 3,
Title: "Hardware Store",
TodoList: []
},
{
Id: 4,
Title: "Costco",
TodoList: [
{
Id: 21,
Title: "Diapers"
},
{
Id: 22,
Title: "Cat Food"
},
{
Id: 23,
Title: "Apples"
},
{
Id: 24,
Title: "Bananas"
}
]
},
{
Id: 5,
Title: "Work",
TodoList: [
{
Id: 34,
Title: "TPS Reports"
}
]
}
];
export default TodoData;
App.Js
import React, { useEffect, useState } from "react";
import TodoData from "./data/Todo.js";
function App() {
const [todoData, setTodoData] = useState([]);
const [todoDetails, setTodoDetails] = useState([]);
useEffect(() => {
if (todoData.length === 0) {
getTodoData();
}
}, [todoData]);
const getTodoData = () => {
setTodoData(TodoData);
console.log("getting todo data");
getTodoDetails(1);
};
const getTodoDetails = id => {
const result = TodoData.filter(x => x.Id === id);
console.log(result[0]);
setTodoDetails(result[0]);
};
const handleClick = e => {
const selectedId = Number(e.target.getAttribute("data-id"));
getTodoDetails(selectedId);
};
return (
<div className="App">
<div className="container-fluid">
<div className="row">
<div className="list-group col-md-4 offset-md-1">
{todoData.map(todos => (
<button
key={todos.Id}
data-id={todos.Id}
className="btn list-group-item d-flex justify-content-between align-items-center"
onClick={handleClick}
>
{todos.Title}
<span className="badge badge-primary badge-pill">
{todos.TodoList.length}
</span>
</button>
))}
</div>
<div className="col-md-6">
<ul className="list-group">
<h2>{todoDetails.Title} List</h2>
{console.log(todoDetails.TodoList)}
{/* this fails miserably */}
{/* {todoDetails.TodoList.map(details => (
<li className="list-group-item" key={details.Id}>
{details.Title}
</li>
))} */}
<li className="list-group-item">Cras justo odio</li>
<li className="list-group-item">Dapibus ac facilisis in</li>
<li className="list-group-item">Morbi leo risus</li>
</ul>
</div>
</div>
</div>
</div>
);
}
export default App;
Q : useEffect - I’m trying to use this to load the data. It keeps complaining about missing dependencies
A : you can ignore it via eslint (react-hooks/exhaustive-deps), there is nothing to worry about
Q : useState - I'm using this to store the data. It's initialized to an empty array. But render is firing before useEffect and it's saying my data is undefined so my second list never renders.
A : Do read the comments in code, hope that will clear your doubts
// you are intializing `todoDetails` with array, when there will be object
// hence the error while mapping inside the html/jsx
// const [todoDetails, setTodoDetails] = useState([]);
// init with `null`, why?
const [todoDetails, setTodoDetails] = useState(null);
// so that you can do something like this
{
todoDetails && ( // <---------- HERE
<ul className="list-group">
<h2>{todoDetails.Title} List</h2>
{console.log(todoDetails.TodoList)}
{/* this fails miserably */}
{todoDetails.TodoList.map(details => (
<li className="list-group-item" key={details.Id}>
{details.Title}
</li>
))}
</ul>
)
}
Q : Now you are getting multiple console.log,
A : the reason behind this is <React.StrictMode>,
React may invoke render phase lifecycles more than once before committing, or it may invoke them without committing at all (because of an error or a higher priority interruption).
I've removed it from index.js in demo, so you can see the diff
WORKING DEMO :
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With