在上一章Todolist with React (3),使用 React-redux 完成了渲染任务清单、和任务新增删除的动作,就让我们继续完成最後一个部分 — Filter 筛选器,控制任务清单的显示。
切换上方的 Filter,可以切换对应的任务清单
首先先处理显示筛选器按钮的部分,被选择的按钮要显示 Selected (黄底) 的样式,总共会有三种状态 SHOW_ALL
、SHOW_TODO
、SHOW_DONE
。
在 filter.js 定义控制 Filter 的 Reducer,State 参数的预设值为 SHOW_ALL
,目前尚未定义 Action,直接回传当前原本的 State。然後要在 index.js 里整合 Filter Reducer。
reducer/filter.js
import * as types from '../actions/ActionTypes';
export default function filter(state = 'SHOW_ALL', action) {
switch (action.type) {
default:
return state;
}
}
reducer/index.js
...
import filterReducer from './filter';
const todoApp = combineReducers({
filterReducer,
todosReducer
});
因为在 TaskList Component 内也会需要 Filter 的状态来显示对应的任务清单,所以我们在 TaskList Component 使用 useSelector
取得目前的 Filter 状态,再把它传入 Filter Component。
components/TaskList.js
...
import { useSelector } from "react-redux";
function TaskList() {
...
const filter = useSelector((store) => store.filterReducer);
const renderItems = ...
return (
<Wrapper>
<Filter selected = {filter}/>
...
</Wrapper>
);
}
利用 Styled-components 根据 Props 可以改变样式的功能,只要按钮是 Selected 的状态,传入的 active
就是 true
,会切换背景颜色变成黄色。
components/Filter.js
const Button = styled.div`
background-color: ${(props) => (props.active ? "#ffc236" : "#bebebe")};
...
`;
function Filter(props) {
return (
<ButtonContainer>
<Button active={props.selected === "SHOW_ALL"}>
ALL
</Button>
<Button active={props.selected === "SHOW_TODO"}>
TODO
</Button>
<Button active={props.selected === "SHOW_DONE"}>
DONE
</Button>
</ButtonContainer>
);
}
可以显示被选择的按钮後,接下来要新增 Filter 切换的功能,在 ActionTypes.js 定义 SET_FILTER
动作。
actions/ActionTypes.js
...
export const SET_FILTER = 'SET_FILTER';
Step1:建立 Action Creator 产生设定 Filter 的动作 Function setFilter
,并取得切换的 filter 名称。
actions/filter.js
import * as types from './ActionTypes';
// action creator
export function setFilter(filter){
return {
type: types.SET_FILTER,
filter
};
}
Step2:处理 Filter Reducer,读取 action.type 为 SET_FILTER 时,直接回传新的 Filter 状态。
reducer/filter.js
import * as types from '../actions/ActionTypes';
export default function filter(state = 'SHOW_ALL', action) {
switch (action.type) {
case types.SET_FILTER:
return action.filter;
default:
return state;
}
}
Step3:完成 Action 和 Reducer 的设定後,在 Filter Component 利用 useDispatch()
来调用 Action。点击 後直接呼叫 setFilter()
,传入对应的筛选器名称。
components/Filter.js
import { useDispatch } from "react-redux";
function Filter(props) {
const dispatch = useDispatch();
return (
<ButtonContainer>
<Button
active={...}
onClick={() => dispatch(actions.setFilter("SHOW_ALL"))}
>
ALL
</Button>
<Button
active={...}
onClick={() => dispatch(actions.setFilter("SHOW_TODO"))}
>
TODO
</Button>
<Button
active={...}
onClick={() => dispatch(actions.setFilter("SHOW_DONE"))}
>
DONE
</Button>
</ButtonContainer>
);
}
切换筛选器的同时,下方的任务清单也要可以根据状态切换对应的列表,我们只在 forEach
里面新增 if
条件式判断,总共会有三种情况:
filter === "SHOW_ALL"
:当 Filter 是 SHOW_ALL
时,判断式永远为 true,显示该任务。filter === "SHOW_TODO" && !item.isCompleted
:当 Filter 是 SHOW_TODO
时,任务的状态 isCompleted
要是 false
,判断式会为 true,才能显示该任务。filter === "SHOW_DONE" && item.isCompleted
:当 Filter 是 SHOW_DONE
时,任务的状态 isCompleted
要是 true,判断式会为 true,才能显示该任务。components/TaskList.js
function TaskList() {
...
const renderItems = () => {
let list = [];
tasks.forEach((item, index) => {
if (
(filter === "SHOW_ALL") ||
(filter === "SHOW_TODO" && !item.isCompleted) ||
(filter === "SHOW_DONE" && item.isCompleted)
) {
list.push(
<TaskItem key={item.taskName} task={{ ...item, idx: index }} />
);
}
});
return list;
};
return (
<Wrapper>
...
<TaskItemContainer>{renderItems()}</TaskItemContainer>
</Wrapper>
);
}
终於完成任务清单和筛选器的功能,剩下最後一个功能 — 完成任务的时候要可以勾选框框,设定任务的状态。一样在 ActionTypes.js 定义勾选任务的动作 TOGGLE_TASK。
actions/ActionTypes.js
...
export const TOGGLE_TASK = 'TOGGLE_TASK';
Step1:建立 Action Creator 产生勾选 Task 的动作 Function toggleTask
,并取得对应的任务索引值。
actions/todos.js
export function toggleTask(idx){
return {
type: types.TOGGLE_TASK,
idx
};
}
Step2:处理 Todo Reducer,读取 action.type 为 TOGGLE_TASK 时,修改该任务的完成状态并回传的新 State。
reducer/todos.js
...
export default function todos(state = initialTasks, action) {
switch (action.type) {
case types.ADD_TASK:...
case types.DELETE_TASK:...
case types.TOGGLE_TASK:
let newState = [...state];
newState[action.idx].isCompleted = !newState[action.idx].isCompleted;
return newState;
default:...
}
}
Step3:完成 Action 和 Reducer 的设定後,在 TaskItem Component 利用 useDispatch()
来调用 Action。点击 <CheckBox />
後直接呼叫 toggleTask()
,传入对应的任务索引值。
components/TaskItem.js
function TaskItem(props) {
const dispatch = useDispatch();
return (
<Container>
<CheckBox
type="checkbox"
checked={...}
onChange={() => dispatch(actions.toggleTask(props.task.idx))}
/>
...
</Container>
);
}
这样就完成了一个简单的 Todolist 罗
如果文章中有错误的地方,要麻烦各位大大不吝赐教;喜欢的话,也要记得帮我按赞订阅喔❤️
>>: Day 28 整体Privacy by Design需求规划评估实作
由於昨天晚上听了明就仁波切的分享,今天原本想读 In Love with the World,但读了...
有了基础的注册系统後,建立资料库来连接系统,用於储存用户、使用者的帐号与密码、等级等,区分版本功能。...
Passing Scrum SASM certification exam with minimum...
曾经被系统的地雷,炸得支离破碎 很多好用的应用程序都对Windows不太友善,今天就让你轻松跨越这些...
Open Street Map 开放街图,OpenStreetMap,简称 OSM,我们把它当成一个...