目录
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_ALL
default:
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 });
};
// 添加todo
const 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">
<input
type="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">
<input
type="checkbox"
checked={todo.isFinished}
onChange={handleChange}
/>
<span
style={{ 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;
效果示意图