In React I have an array of objects as a state. Let’s say they are "todos". I also have two divs. One div is for incomplete tasks, second is for completed tasks. During mapping I’m using <Todo/> component.
const [todos, setTodos] = useState([
{id: 1, text: 'Lorem', isComplete: true},
{id: 2, text: 'Ipsum', isComplete: true}],
{id: 3, text: 'Test', isComplete: false})
]);
in return I have an HTML structure:
return (
<div>
<h1>Todos</h1>
<p>My todos for today:</p>
<div id="incomplete"></div>
<p>Todos that've been already done:</p>
<div id="complete"></div>
</div> )
Mapping looks something like this:
todos.map(todo => {
if(todo.isComplete){
return <Todo
id={todo.id}
text={todo.text}
isComplete={todo.isComplete}/>
// AND HERE I WANT TO PUSH THIS COMPONENT INTO div#complete.
} })
I’m expecting something like this:
return (
<div>
<h1>Todos</h1>
<p>My todos for today:</p>
<div id="incomplete">
<div className="task">
<p>Test</p>
</div>
<div className="task">
<p>Ipsum</p>
</div>
</div>
<p>Todos that've been already done:</p>
<div id="complete">
<div className="task">
<p>Lorem</p>
</div>
</div>
</div> )
>Solution :
Use filter() before map() to get only the (in)/complete:
return (
<div>
<h1>Todos</h1>
<p>My todos for today:</p>
<div id="incomplete">
{todos.filter(t => !t.isComplete).map(e => <Todo ...{} />)}
</div>
<p>Todos that've been already done:</p>
<div id="complete">
{todos.filter(t => t.isComplete).map(e => <Todo ...{} />)}
</div>
</div>
)
React Demo:
const { useState } = React;
const Todo = (props) => {
return <p>{props.text}</p>;
}
const Example = () => {
const [todos, setTodos] = useState([
{id: 1, text: 'Lorem', isComplete: true},
{id: 2, text: 'Ipsum', isComplete: true},
{id: 3, text: 'Test', isComplete: false}
]);
return (
<div>
<h1>Todos</h1>
<p>My todos for today:</p>
<div id="incomplete">
{todos.filter(t => !t.isComplete).map(e => <Todo {...e} />)}
</div>
<p>Todos that've been already done:</p>
<div id="complete">
{todos.filter(t => t.isComplete).map(e => <Todo {...e} />)}
</div>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Based on OP’s edit, you can introduce a function like getTodos that will accept a boolean, and create the filter function based on that. Then return <Todo /> accordingly, this will reduce the duplicate filter(), map() and <Todo ... /> so you’ll just need these 2 in the render:
<div id="incomplete">
{getTodos()}
</div>
// ....
<div id="complete">
{getTodos(true)}
</div>
React Demo:
const { useState } = React;
const Todo = (props) => {
return <p>{props.text}</p>;
}
const Example = () => {
const [todos, setTodos] = useState([
{id: 1, text: 'Lorem', isComplete: true},
{id: 2, text: 'Ipsum', isComplete: true},
{id: 3, text: 'Test', isComplete: false}
]);
const getTodos = (complete) => {
const filterFunction = (complete) ? (t => t.isComplete) : (t => !t.isComplete);
return todos.filter(filterFunction).map(e => {
return <Todo {...e} />;
});
}
return (
<div>
<h1>Todos</h1>
<p>My todos for today:</p>
<div id="incomplete">
{getTodos()}
</div>
<p>Todos that've been already done:</p>
<div id="complete">
{getTodos(true)}
</div>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>