how to create a rendering condition for 3 options? The ternary operator is insufficient for this option and the code I wrote in my opinion is not quite ok.
import React, { useEffect } from "react";
import { useParams } from "react-router-dom";
import { useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { getTodoItems, setUrlParams } from "../redux/todoSlice";
import TodoItem from "./TodoItem";
const TodoList = ({ filter }) => {
const { id } = useParams();
const dispatch = useDispatch();
const { searchTerm, todoList } = useSelector((state) => state.todo);
useEffect(() => {
dispatch(getTodoItems(id));
dispatch(setUrlParams( id));
}, [dispatch, id]);
const searchedItems = todoList?.filter((todo) => {
if (!searchTerm) {
return todo;
} else {
return todo?.title.toLowerCase().includes(searchTerm);
}
});
// FROM HERE
const filteredItems = (filter) => {
if (filter === "all") {
return searchedItems?.map((todo, id) => (
<TodoItem key={id} data={todo} />
));
} else if (filter === "active") {
return searchedItems
?.filter((todo) => !todo.isCompleted)
.map((todo, id) => <TodoItem key={id} data={todo} />);
} else if (filter === "done") {
return searchedItems
?.filter((todo) => todo.isCompleted)
.map((todo, id) => <TodoItem key={id} data={todo} />);
}
};
return (
<div>
{filter === "all" && filteredItems("all")}
{filter === "active" && filteredItems("active")}
{filter === "done" && filteredItems("done")}
</div>
);
};
export default TodoList;
Can you please tell me how to make the code more efficient and simpler?
CodePudding user response:
You can use Object literal
functionality here. You can define your filteredItems
as an object and render them with the type.
const filteredItems = (filter) => {
return {
all: searchedItems?.map((todo, id) => <TodoItem key={id} data={todo} />),
active: searchedItems
?.filter((todo) => !todo.completed)
.map((todo, id) => <TodoItem key={id} data={todo} />),
done: searchedItems
?.filter((todo) => todo.completed)
.map((todo, id) => <TodoItem key={id} data={todo} />),
}[filter];
};
return (
<div>
{filterRender(filter)}
</div>
);
CodePudding user response:
I think that the main problem here is the conditional redundancy, you are doing the same validation two times, I would remove all the if conditions from filteredItems
and move each returned TodoItem into his own function, like this:
const TodoList = ({ filter }) => {
const { id } = useParams()
const dispatch = useDispatch()
const { searchTerm, todoList } = useSelector(state => state.todo)
useEffect(() => {
dispatch(getTodoItems(id))
dispatch(setUrlParams( id))
}, [dispatch, id])
const searchedItems = todoList?.filter(todo => {
if (!searchTerm) {
return todo
} else {
return todo?.title.toLowerCase().includes(searchTerm)
}
})
const AllItems = () => {
return searchedItems?.map((todo, id) => <TodoItem key={id} data={todo} />)
}
const activeItems = () => {
return searchedItems
?.filter(todo => !todo.isCompleted)
.map((todo, id) => <TodoItem key={id} data={todo} />)
}
const doneItems = () => {
return searchedItems
?.filter(todo => todo.isCompleted)
.map((todo, id) => <TodoItem key={id} data={todo} />)
}
return (
<div>
{filter === 'all' && AllItems()}
{filter === 'active' && activeItems()}
{filter === 'done' && doneItems()}
</div>
)
}
CodePudding user response:
I'd probably have done something like filter followed by map.
const filteredItems = (filter) => {
let filtered = searchedItems;
if (filter === "active")
filtered = searchedItems
?.filter((todo) => !todo.isCompleted)
if (filter === "done")
filtered = searchedItems
?.filter((todo) => todo.isCompleted)
return filtered.map((todo, id) => <TodoItem key={id} data={todo} />);
};
return (
<div>
{filteredItems(filter)}
</div>
);