目录
1. store.ts
2. reducer.ts
3. ReduxProvider.tsx
4. mapStateToProps.ts
5. mapDispatchToProps.ts
6. Todo组件(最外层包ReduxProvider
7. Todo组件里面涉及的子组件
1) TodoInput.tsx
2) TodoList.tsx
3) TodoItem.tsx
8. App组件使用Todo组件
1. store.ts
参考网站: GitHub - zalmoxisus/redux-devtools-extension: Redux DevTools extension.
下载谷歌扩展插件的地址: react-redux-devtools: react-devtools-v3react-devtools-v4redux-devtools
import { applyMiddleware, combineReducers, legacy_createStore as createStore } from 'redux';
import { composeWithDevTools } from "redux-devtools-extension";
import thunk from 'redux-thunk';
import { todos, visibilityFilter } from './reduer';// 使用 redux-devtools
const composeEnhancers = composeWithDevTools({// options like actionSanitizer, stateSanitizer});// 使用 redux-thunk 中间件const enhancer = composeEnhancers(applyMiddleware(thunk));
export default createStore(combineReducers({ todos, visibilityFilter }), enhancer);
2. reducer.ts
export const visibilityFilter = (state = 'SHOW_ALL', action) => {switch (action.type) {// 设置显示类型(所有、完成、未完成)case 'SET_VISIBILITY_FILTER':return action.filter// 默认是 SHOW_ALLdefault:return state}}// 新增列表数据和改变数组数据// 将业务逻辑拆分到一个单独文件中,方便进行状态管理
export interface StateProps {id: number;text: string;isFinished: boolean;}export interface ActionProps {type: string;[key: string]: any;}
export const todos = (state: StateProps[] | [], action: ActionProps) => {console.log(state, action);switch (action.type) {case "ADD":return [...state, action.todo];case "CHANGESTATUS":return state.map((item) => {if (item.id === action.id) {return Object.assign({}, item, { isFinished: !item.isFinished });}return item;});default:return state || [];}};
3. ReduxProvider.tsx
import React from "react";
import { Provider } from "react-redux";
import store from './store';const ReduxProvider = (props) => {return <Provider store={store}>{props.children}</Provider>;
};export default ReduxProvider
4. mapStateToProps.ts
// 不同类型的 todo 列表
const getVisibleTodos = (todos, filter) => {switch (filter) {case "SHOW_ALL": // 全部显示return todos;case "SHOW_FINISHED":return todos.filter((t) => t.isFinished);case "SHOW_NOT_FINISH":return todos.filter((t) => !t.isFinished);default:return todos;}
};const mapStateToProps = (state) => {return {// 根据完成状态,筛选数据todoList: getVisibleTodos(state.todos, state.visibilityFilter),};
};export default mapStateToProps;
5. mapDispatchToProps.ts
import { StateProps } from "./reduer";const mapDispatchToProps = (dispatch) => {const changeTodo = (id: number) => {dispatch({ type: "CHANGESTATUS", id });};// 添加todoconst addTodo = (todo: StateProps) => {dispatch({ type: "ADD", todo });};// 显示已完成的const showFinished = () => {dispatch({ type: "SET_VISIBILITY_FILTER", filter: 'SHOW_FINISHED' });}// 显示未完成的const showNotFinish = () => {dispatch({ type: "SET_VISIBILITY_FILTER", filter: 'SHOW_NOT_FINISH' });}// 显示全部完成的const showAll = () => {dispatch({ type: "SET_VISIBILITY_FILTER", filter: 'SHOW_ALL' });}return {addTodo,// 切换完成状态changeTodo,showFinished,showNotFinish,showAll,};};export default mapDispatchToProps
6. Todo组件(最外层包ReduxProvider
import React from "react";
import ReduxProvider from "./ReduxProvider";
import { TodoInput } from "./TodoInput";
import { TodoList } from "./TodoList";// 父组件
export const Todo = () => {return (<ReduxProvider><TodoInput /><TodoList /></ReduxProvider>)
}
7. Todo组件里面涉及的子组件
1) TodoInput.tsx
import React from "react";
import { useState } from "react";
import mapStateToProps from "./mapStateToProps";
import mapDispatchToProps from "./mapDispatchToProps";
import { connect } from "react-redux";// 子组件
const TodoInput0 = (props) => {const [text, setText] = useState("");const { addTodo, showAll, showFinished, showNotFinish } = props;const handleChangeText = (e: React.ChangeEvent) => {setText((e.target as HTMLInputElement).value);};const handleAddTodo = () => {if (!text) return;addTodo({id: new Date().getTime(),text: text,isFinished: false,});setText("");};return (<div className="todo-input"><inputtype="text"placeholder="请输入代办事项"onChange={handleChangeText}value={text}/><button style={{ marginLeft: "10px" }} onClick={handleAddTodo}>+添加</button><button style={{ marginLeft: "10px" }} onClick={showAll}>show all</button><button style={{ marginLeft: "10px" }} onClick={showFinished}>show finished</button><button style={{ marginLeft: "10px" }} onClick={showNotFinish}>show not finish</button></div>);
};const TodoInput = connect(mapStateToProps, mapDispatchToProps)(TodoInput0);
export { TodoInput };
2) TodoList.tsx
import React from "react";
import { TodoItem } from "./TodoItem";
import _ from "lodash";
import { connect } from "react-redux";
import mapStateToProps from "./mapStateToProps";
import mapDispatchToProps from "./mapDispatchToProps";const TodoList0 = (props) => {const { todoList } = props;return (<div className="todo-list">{_.map(todoList, (item) => (<TodoItem key={_.get(item, "id")} todo={item || {}} />))}</div>);
};const TodoList = connect(mapStateToProps, mapDispatchToProps)(TodoList0);
export { TodoList };
3) TodoItem.tsx
import React from "react";
import _ from "lodash";
import { connect } from "react-redux";
import mapStateToProps from "./mapStateToProps";
import mapDispatchToProps from "./mapDispatchToProps";// 孙子组件
const TodoItem0 = (props) => {const { todo, changeTodo } = props;// 改变事项状态const handleChange = () => {changeTodo(_.get(todo, "id"));};return (<div className="todo-item"><inputtype="checkbox"checked={todo.isFinished}onChange={handleChange}/><spanstyle={{ textDecoration: todo.isFinished ? "line-through" : "none" }}>{todo.text}</span></div>);
};
const TodoItem = connect(mapStateToProps, mapDispatchToProps)(TodoItem0);
export { TodoItem };
8. App组件使用Todo组件
import React from "react";
import { Todo } from "./reduxConnectProvider/Todo";const App: React.FC = () => {return (<><Todo /></>);
};export default App;
效果示意图