- import { atom, useRecoilState } from 'recoil';
-
- const initState = atom({
- key: 'initState',
- default: {
- state: [],
- },
- })
-
- // 将业务逻辑拆分到一个单独文件中,方便进行状态管理
- export interface StateProps {
- id: number;
- text: string;
- isFinished: boolean;
- }
- export interface ActionProps {
- type: string;
- [key: string]: any;
- }
- export const reducer = (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;
- }
- }
-
- export const useProvider = () => {
- // 改变todo
- const [context, dispatch]: any = useRecoilState(initState);
-
- const changeTodo = (id: number) => {
- const todoList = reducer(context.state, { type: 'CHANGESTATUS', id: id })
- dispatch({ state: todoList });
- }
- // 添加todo
- const addTodo = (todo: StateProps) => {
- const todoList = reducer(context.state, { type: 'ADD', todo })
- dispatch({ state: todoList });
- }
- return { changeTodo, addTodo, todoList: context.state };
- }
- import { TodoInput } from "./TodoInput";
- import { TodoList } from "./TodoList";
-
- // 父组件
- export const Todo = () => {
- return (
- <>
- <TodoInput />
- <TodoList />
- </>
- )
- }
- import { useState } from "react";
- import _ from 'lodash';
- import { useProvider } from "./useProvider";
-
-
- // 子组件
- export const TodoInput = () => {
- const [text, setText] = useState('');
- const {addTodo} = useProvider();
- 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>
- </div>
- )
- }
- import { useProvider } from "./useProvider";
- import _ from 'lodash';
-
- // 孙子组件
- export const TodoItem = ({ todo }: {
- todo:any;
- key: any;
- }) => {
- const {changeTodo} = useProvider();
- // 改变事项状态
- 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>
- )
- }
- import { TodoItem } from "./TodoItem";
- import { useProvider } from "./useProvider";
- import _ from 'lodash';
-
- export const TodoList = () => {
- const {todoList} = useProvider();
- return (
- <div className="todo-list">
- {_.map(todoList, item => <TodoItem key={_.get(item, 'id')} todo={item||{}} />)}
- </div>
- )
- }
- import { RecoilRoot } from 'recoil';
- import './App.css';
- import React from 'react';
- import ErrorBoundary from './ErrorBoundary';
- import { Todo } from './recoilProvider/Todo';
-
-
-
- const App:React.FC = ()=> {
- return (
- <RecoilRoot>
- <ErrorBoundary>
- <React.Suspense fallback={<div>Loading...</div>}>
- <div className='App'>
- <Todo />
- </div>
- </React.Suspense>
- </ErrorBoundary>
- </RecoilRoot>
- );
- }
-
- export default App;

- import { createContext, useContext } from "react";
-
- // 将业务逻辑拆分到一个单独文件中,方便进行状态管理
- export interface StateProps {
- id: number;
- text: string;
- isFinished: boolean;
- }
- export interface ActionProps {
- type: string;
- [key: string]: any;
- }
- export const reducer = (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;
- }
- }
-
-
- export interface ContextProps {
- state: StateProps[];
- dispatch: React.Dispatch<ActionProps>;
- }
- // const MyContext = createContext<ContextProps | null>(null); // 泛型写法
- export const MyContext = createContext({} as ContextProps); // 断言写法
-
- export const useProvider = () => {
- // 改变todo
- const context = useContext(MyContext);
- const changeTodo = (id: number) => {
- context.dispatch({ type: 'CHANGESTATUS', id: id });
- }
- // 添加todo
- const addTodo = (todo: StateProps) => {
- context.dispatch({ type: 'ADD', todo });
- }
- return { changeTodo, addTodo, todoList: context.state, context };
- }
- import { useContext, useReducer } from "react";
- import { MyContext, StateProps, reducer } from "./useProvider";
-
-
- const ContextProvider = (props: React.PropsWithChildren<{}>) => {
- const context = useContext(MyContext);
- const initState: StateProps[] = context.state || [];
- const [state, dispatch] = useReducer(reducer, initState);
-
- return (
- <MyContext.Provider value={{ state, dispatch }} >
- {/* 插槽内容 */}
- {props.children}
- </MyContext.Provider>
- )
- }
-
- export default ContextProvider;
- import ContextProvider from "./ContextProvider";
- import { TodoInput } from "./TodoInput";
- import { TodoList } from "./TodoList";
-
- // 父组件
- export const Todo = () => {
- return (
- <ContextProvider>
- <TodoInput />
- <TodoList />
- </ContextProvider>
- )
- }
TodoInput, TodoItem和TodoList 组件不变(使用recoil那块的文件代码)
直接使用

点击添加按钮,新增一列,点击多选框(选中)中划线一行,取消选中该行就恢复正常
- import { useState } from "react";
- import { createStore } from "redux";
-
- // 将业务逻辑拆分到一个单独文件中,方便进行状态管理
- export interface StateProps {
- id: number;
- text: string;
- isFinished: boolean;
- }
- export interface ActionProps {
- type: string;
- [key: string]: any;
- }
- export const reducer = (
- 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;
- }
- };
-
- export interface ContextProps {
- state: StateProps[];
- dispatch: React.Dispatch<ActionProps>;
- }
-
- export const store = createStore(reducer, []);
- export const useProvider = () => {
- const[todoList, setTodoList] = useState(store.getState())
- // 改变todo
- const changeTodo = (id: number) => {
- store.dispatch({ type: 'CHANGESTATUS', id: id });
- }
- // 添加todo
- const addTodo = (todo: StateProps) => {
- store.dispatch({ type: 'ADD', todo });
- }
- store.subscribe(()=> {
- setTodoList(store.getState())
- })
-
- return { changeTodo, addTodo, todoList, store };
- }
-
- import { Provider } from "react-redux";
- import { store } from "./useProvider";
-
- const ReduxProvider = (props) => {
- return <Provider store={store}>{props.children}</Provider>;
- };
-
- export default ReduxProvider;
- import ReduxProvider from "./ReduxProvider";
- import { TodoInput } from "./TodoInput";
- import { TodoList } from "./TodoList";
-
- // 父组件
- export const Todo = () => {
- return (
- <ReduxProvider>
- <TodoInput />
- <TodoList />
- </ReduxProvider>
- )
- }
TodoInput, TodoItem和TodoList 组件不变
- const App:React.FC = ()=> {
- return <Todo />
- }
-
- export default App;
数据更新, 视图跟着更新靠的却是store.subsribe(() => { 给useState的变量赋值 }); 不符合逻辑习惯, 理论上应该修改数据, 随之页面自动渲染, 不建议依靠store.subsribe

注意:
1) 普通用法需要store.subscribe再赋值给useState, 通过useState的变量才能让页面正常随着数据变得更新
2) useDispatch, useSelector解决这个痛点
- import {configureStore, createSlice} from '@reduxjs/toolkit'
- import _ from 'lodash'
- import { useDispatch, useSelector } from "react-redux";
-
- // 将业务逻辑拆分到一个单独文件中,方便进行状态管理
- export interface StateProps {
- id: number;
- text: string;
- isFinished: boolean;
- }
- export interface ActionProps {
- type: string;
- [key: string]: any;
- }
-
- export const storeSlice = createSlice({
- name: 'todoList',
- initialState: {
- value: []
- },
- reducers: {
- toggle: (state, action) => {
- const id = _.get(action, 'payload.id')
- const arr = state.value
- state.value = _.map(arr, item => {
- if (item.id === id) {
- return Object.assign({}, item, { isFinished: !item.isFinished });
- }
- return item;
- })
-
- return state
- },
- add: (state, action) => {
- console.log(state, action,)
- const arr = state.value as any || [] ;
- const todo = _.get(action, 'payload.todo')
- if(todo) {
- state.value = todo? [...arr, todo]: arr
- }
-
- return state
- },
- }
- })
-
- export const store = configureStore({reducer: storeSlice.reducer})
-
- export const useProvider = () => {
- const { toggle, add } = storeSlice.actions;
- const todoList = useSelector((state) => {
- return _.get(state, 'value');
- });
- const dispatch = useDispatch();
- // 改变todo
- const changeTodo = (id: number) => {
- dispatch((toggle({ id })));
- }
- // 添加todo
- const addTodo = (todo: StateProps) => {
- dispatch(add({ todo }));
- }
-
- return { changeTodo, addTodo, todoList, store };
- }
-
- import { Provider } from "react-redux";
- import { store } from "./useProvider";
-
- const ReduxProvider = (props) => {
- return <Provider store={store}>{props.children}</Provider>;
- };
-
- export default ReduxProvider;
- import ReduxProvider from "./ReduxProvider";
- import { TodoInput } from "./TodoInput";
- import { TodoList } from "./TodoList";
-
- // 父组件
- export const Todo = () => {
- return (
- <ReduxProvider>
- <TodoInput />
- <TodoList />
- </ReduxProvider>
- )
- }
TodoInput, TodoItem和TodoList 组件不变
- const App:React.FC = ()=> {
- return <Todo />
- }
-
- export default App;

- import { configureStore, createSlice } from "@reduxjs/toolkit";
- import _ from "lodash";
- import { useDispatch, useSelector } from "react-redux";
- import { persistStore, persistReducer } from "redux-persist";
- import storage from "redux-persist/lib/storage";
-
- // 将业务逻辑拆分到一个单独文件中,方便进行状态管理
- export interface StateProps {
- id: number;
- text: string;
- isFinished: boolean;
- }
- export interface ActionProps {
- type: string;
- [key: string]: any;
- }
-
- export const storeSlice = createSlice({
- name: "todoList",
- initialState: {
- value: [],
- },
- reducers: {
- toggle: (state, action) => {
- const id = _.get(action, "payload.id");
- const arr = state.value;
- state.value = _.map(arr, (item) => {
- if (item.id === id) {
- return Object.assign({}, item, { isFinished: !item.isFinished });
- }
- return item;
- });
-
- return state;
- },
- add: (state, action) => {
- console.log(state, action);
- const arr = (state.value as any) || [];
- const todo = _.get(action, "payload.todo");
- if (todo) {
- state.value = todo ? [...arr, todo] : arr;
- }
-
- return state;
- },
- },
- });
-
- const reducer = storeSlice.reducer;
-
- // 定义持久化配置
- const persistConfig = { key: storeSlice.name, storage };
- // 创建持久化reducer
- export const persistedReducer = persistReducer(persistConfig, reducer);
- export const store = configureStore({
- reducer: persistedReducer, // 解决了序列化问题
- middleware: (getDefaultMiddleware) =>
- getDefaultMiddleware({ serializableCheck: false }),
- });
- // 创建持久化存储器
- export const persistor = persistStore(store);
-
- export const useProvider = () => {
- const { toggle, add } = storeSlice.actions;
- const todoList = useSelector((state) => {
- return _.get(state, "value");
- });
- const dispatch = useDispatch();
- // 改变todo
- const changeTodo = (id: number) => {
- dispatch(toggle({ id }));
- };
- // 添加todo
- const addTodo = (todo: StateProps) => {
- dispatch(add({ todo }));
- };
-
- return { changeTodo, addTodo, todoList, store };
- };
- import { Provider } from "react-redux";
- import { persistor, store } from "./useProvider";
- import { PersistGate } from "redux-persist/integration/react";
- import React from "react"; // 有些编译会还要求必须把react引入, 没有使用也要引入
-
- const ReduxProvider = (props) => {
- return (
- <Provider store={store}>
- <PersistGate loading={null} persistor={persistor}>
- {props.children}
- </PersistGate>
- </Provider>
- );
- };
-
- export default ReduxProvider;
- import React from "react";
- import ReduxProvider from "./ReduxProvider";
- import { TodoInput } from "./TodoInput";
- import { TodoList } from "./TodoList";
-
- // 父组件
- const Todo = () => {
- return (
- <ReduxProvider>
- <TodoInput />
- <TodoList />
- </ReduxProvider>
- )
- }
- export default Todo;
TodoInput, TodoItem和TodoList 组件不变, 如果报错: Todo.tsx:8 Uncaught ReferenceError: React is not defined, 就把import React from "react";加上, 没有使用React也引入一下就不会报错了
- import React, { lazy } from "react";
- // import Todo from './reduxPersistProvider/Todo';
- const Todo = lazy(() => import("./reduxPersistProvider/Todo"));
-
- const App: React.FC = () => {
- return <Todo />;
- };
-
- export default App;
效果图如下(就不用担心刷新页面数据就丢失了):
适用于需要存储字典对象等功能

redux toolkit文档地址:
- import {
- configureStore,
- createAsyncThunk,
- createSlice,
- } from "@reduxjs/toolkit";
- import _ from "lodash";
- import { useDispatch, useSelector } from "react-redux";
- import { persistStore, persistReducer } from "redux-persist";
- import storage from "redux-persist/lib/storage";
- import axios from "./api";
-
- // 异步函数
- export const fetchHomeMultidataAction = createAsyncThunk(
- "todoList/remmend",
- async (extraInfo, { dispatch }) => {
- console.log(extraInfo, "dispatch", 66666666);
- const { data } = await axios.get("home_page");
- return data;
- }
- );
-
- export const clearRecommendsAction = createAsyncThunk(
- "todoList/clear-recommends",
- async (extraInfo, params) => {
- console.log(extraInfo, params, "clear-recommends");
- const arr = await Promise.resolve([]);
- return arr;
- }
- );
-
- // 将业务逻辑拆分到一个单独文件中,方便进行状态管理
- export interface StateProps {
- id: number;
- text: string;
- isFinished: boolean;
- }
- export interface ActionProps {
- type: string;
- [key: string]: any;
- }
-
- export const storeSlice = createSlice({
- name: "todoList",
- initialState: {
- checkboxList: [],
- searchRecomments: [],
- filterTag: "",
- },
- reducers: {
- toggle: (state, action) => {
- const id = _.get(action, "payload.id");
- const arr = state.checkboxList;
- state.checkboxList = _.map(arr, (item) => {
- if (item.id === id) {
- return Object.assign({}, item, { isFinished: !item.isFinished });
- }
- return item;
- });
-
- return state;
- },
- add: (state, action) => {
- const arr = (state.checkboxList as any) || [];
- const todo = _.get(action, "payload.todo");
- if (todo) {
- state.checkboxList = todo ? [...arr, todo] : arr;
- }
-
- return state;
- },
- filter: (state, { payload }) => {
- console.log(payload, "payload");
- state.filterTag = payload;
-
- return state;
- },
- },
- // 异步处理
- // extraReducers: {
- // // 处于padding状态时回调
- // [fetchHomeMultidataAction.pending](state, { payload }) {
- // console.log("正处于pending状态", state, payload);
- // return state;
- // },
- // // 处于fulfilled状态时回调
- // [fetchHomeMultidataAction.fulfilled](state, { payload }) {
- // console.log("已经处于fulfilled状态", state, payload);
- // state.searchRecomments = _.get(payload, "searchRecomments");
- // return state;
- // },
- // // 处于rejected状态时回调
- // [fetchHomeMultidataAction.rejected](state, { payload }) {
- // console.log("正处于rejected状态", state, payload);
- // return state;
- // },
- // // 清空数组
- // [clearRecommendsAction.fulfilled](state, { payload }) {
- // console.log("clearRecommendsAction--fullfilled", state, payload);
- // state.searchRecomments = [];
- // return state;
- // },
- // },
- extraReducers: ({ addCase }) => {
- // 处于padding状态时回调
- addCase(fetchHomeMultidataAction.pending, (state, { payload }) => {
- console.log("正处于pending状态", state, payload);
- return state;
- })
- // 处于fulfilled状态时回调
- .addCase(fetchHomeMultidataAction.fulfilled, (state, { payload }) => {
- console.log("已经处于fulfilled状态", state, payload);
- state.searchRecomments = _.get(payload, "searchRecomments");
- return state;
- })
- // 处于rejected状态时回调
- .addCase(fetchHomeMultidataAction.rejected, (state, { payload }) => {
- console.log("正处于rejected状态", state, payload);
- return state;
- })
- // 清空数组
- .addCase(clearRecommendsAction.fulfilled, (state, { payload }) => {
- console.log("clearRecommendsAction--fullfilled", state, payload);
- state.searchRecomments = [];
- return state;
- });
- },
- });
-
- const reducer = storeSlice.reducer;
-
- // 定义持久化配置
- const persistConfig = { key: storeSlice.name, storage };
- // 创建持久化reducer
- export const persistedReducer = persistReducer(persistConfig, reducer);
- export const store = configureStore({
- reducer: persistedReducer, // 解决了序列化问题
- middleware: (getDefaultMiddleware) =>
- getDefaultMiddleware({ serializableCheck: false }),
- });
- // 创建持久化存储器
- export const persistor = persistStore(store);
-
- export const useProvider = () => {
- const { add, toggle, filter } = storeSlice.actions;
-
- // 不同类型的 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 todoList = useSelector((state) => {
- const arr = _.get(state, "checkboxList") || [];
- const filterTag = _.get(state, "filterTag");
- return getVisibleTodos(arr, filterTag) as StateProps[] || [];
- });
- const searchRecomments = useSelector((state) => {
- return _.get(state, "searchRecomments");
- });
- const dispatch = useDispatch();
- // 改变todo
- const changeTodo = (id: number) => {
- dispatch(toggle({ id }));
- };
- // 添加todo
- const addTodo = (todo: StateProps) => {
- dispatch(add({ todo }));
- };
-
- // 筛选todo列表
- const onFilterTodoList = (filterTag) => {
- dispatch(filter(filterTag));
- };
-
- const showAll = () => onFilterTodoList("SHOW_ALL");
- const showFinished = () => onFilterTodoList("SHOW_FINISHED");
- const showNotFinish = () => onFilterTodoList("SHOW_NOT_FINISH");
-
- // 异步获取推荐数据
- const asyncGetRemments = () => {
- dispatch(fetchHomeMultidataAction([]));
- };
- const asyncClearRemments = () => {
- dispatch(clearRecommendsAction([]));
- };
-
- return {
- changeTodo,
- addTodo,
- todoList,
- store,
- searchRecomments,
- asyncGetRemments,
- showAll,
- showFinished,
- showNotFinish,
- asyncClearRemments,
- };
- };
- import { Provider } from "react-redux";
- import { persistor, store } from "./useProvider";
- import { PersistGate } from "redux-persist/integration/react";
- import React from "react"; // 有些编译会还要求必须把react引入, 没有使用也要引入
-
- const ReduxProvider = (props) => {
- return (
- <Provider store={store}>
- <PersistGate loading={null} persistor={persistor}>
- {props.children}
- </PersistGate>
- </Provider>
- );
- };
-
- export default ReduxProvider;
- import React, { lazy } from "react";
- // import ReduxProvider from "./ReduxProvider";
- // import TodoList from "./TodoList";
- // import TodoInput from "./TodoInput";
-
- const ReduxProvider = lazy(() => import("./ReduxProvider"));
- const TodoList = lazy(() => import("./TodoList"));
- const TodoInput = lazy(() => import("./TodoInput"));
-
- // 父组件
- const Todo = () => {
- return (
- <ReduxProvider>
- <TodoInput />
- <TodoList />
- </ReduxProvider>
- );
- };
- export default Todo;
- import React, { useState } from "react";
- import { useProvider } from "./useProvider";
- import "./TodoInput.less";
-
- // 子组件
- const TodoInput = () => {
- const [text, setText] = useState("");
- const {
- addTodo,
- asyncGetRemments,
- showAll,
- showFinished,
- showNotFinish,
- asyncClearRemments,
- } = useProvider();
- 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 onClick={handleAddTodo}>+添加</button>
- <button onClick={asyncGetRemments}>异步获取推荐列表数据</button>
- <button onClick={asyncClearRemments}>前端清空推荐列表</button>
- <button onClick={showAll}>show all</button>
- <button onClick={showFinished}>show finished</button>
- <button onClick={showNotFinish}>show not finish</button>
- </div>
- );
- };
-
- export default TodoInput;
- import { useProvider } from "./useProvider";
- import _ from 'lodash';
- import React from "react";
-
- // 孙子组件
- export const TodoItem = ({ todo }: {
- todo:any;
- key: any;
- }) => {
- const {changeTodo} = useProvider();
- // 改变事项状态
- 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>
- )
- }
- import { TodoItem } from "./TodoItem";
- import { useProvider } from "./useProvider";
- import _ from "lodash";
- import React from "react";
-
- const TodoList = () => {
- const { todoList, searchRecomments } = useProvider();
- return (
- <>
- <p>checckbox-list: </p>
- <div className="todo-list">
- {_.map(todoList, (item) => (
- <TodoItem key={_.get(item, "id")} todo={item || {}} />
- ))}
- </div>
- <hr/>
- <p>推荐列表recommends-list: </p>
- <ul className="recommends-list">
- {_.map(searchRecomments, (item) => (
- <li key={_.get(item, "value")}>{_.get(item, "label")}</li>
- ))}
- </ul>
- </>
- );
- };
-
- export default TodoList
App组件:
- import React, { Suspense, lazy } from "react";
- // import Todo from "./reduxAsyncProvider/Todo";
- import { Spin } from "antd";
- const Todo = lazy(() => import("./reduxAsyncProvider/Todo"));
-
- const App: React.FC = () => {
- return (
- <Suspense fallback={<Spin />}>
- <Todo />
- </Suspense>
- );
- };
-
- export default App;
- import axios from "axios";
-
-
- const instance = axios.create({
- baseURL: '/api', // 设置请求的前缀
- })
-
- instance.interceptors.response.use((response)=> {
- const {data:_data} = response;
- const {data, code,msg} = _data
- if(code !== 0) {
- console.log(code, msg, data, response)
- return Promise.reject(response)
- }
- return response.data
- })
-
- export default instance
- const path = require('path')
- const jsonServer = require('json-server')
- const router = require('./router')
- const db = require('./db')()
-
- const server = jsonServer.create()
-
- const middlewares = jsonServer.defaults({
- static: path.join(__dirname, '../public')
- })
- server.use(middlewares)
- // req.body
- server.use(jsonServer.bodyParser)
-
-
- server.use((req, res, next) => {
- const json = res.json.bind(res)
- res.success = (data) => {
- return json({
- code: 0,
- msg: '请求成功',
- data
- })
- }
- res.fail = (msg, code = -1, data) => {
- return json({
- code,
- msg,
- data
- })
- }
- next()
- })
-
- router(server)
- const jsonRouter = jsonServer.router(db)
- server.use((req, res, next) => {
- setTimeout(next, 1000)
- })
- server.use('/api', jsonRouter)
-
- server.listen(8000, () => {
- console.log('======JSON Server is running at 8000')
- })
- const homePage = require('./home_page')
- function responseData(data) {
- return {
- code: 0,
- msg: '请求成功',
- data,
- }
- }
-
- module.exports = () => {
- return {
- // 客户端调用axios.get('/api/home_page').then(res=>{})
- home_page: responseData(homePage()),
- }
- }
- module.exports = () => {
- return {
- searchRecomments: [
- {
- value: 0,
- label: '牛腩',
- },
- {
- value: 1,
- label: '色拉',
- },
- {
- value: 2,
- label: '奶茶',
- },
- {
- value: 3,
- label: '西瓜汁',
- },
- ],
- banner: [
- {
- imgUrl: '/imgs/index_page/transformer-banner.png',
- },
- ],
- transformer: [
- {
- label: '美食外卖',
- imgUrl: '/imgs/index_page/transformer-icon1.png',
- },
- {
- label: '超市便利',
- imgUrl: '/imgs/index_page/transformer-icon2.png',
- },
- {
- label: '美食团购',
- imgUrl: '/imgs/index_page/transformer-icon3.png',
- },
- {
- label: '丽人/医美',
- imgUrl: '/imgs/index_page/transformer-icon4.png',
- },
- {
- label: '休闲玩乐',
- imgUrl: '/imgs/index_page/transformer-icon5.png',
- },
- {
- label: '下午茶',
- imgUrl: '/imgs/index_page/transformer-icon6.png',
- },
- {
- label: '水果',
- imgUrl: '/imgs/index_page/transformer-icon7.png',
- },
- {
- label: '鲜花绿植',
- imgUrl: '/imgs/index_page/transformer-icon8.png',
- },
- {
- label: '买菜',
- imgUrl: '/imgs/index_page/transformer-icon9.png',
- },
- {
- label: '甜品饮品',
- imgUrl: '/imgs/index_page/transformer-icon10.png',
- },
- {
- label: '全城购',
- imgUrl: '/imgs/index_page/transformer-icon11.png',
- },
- {
- label: '送药上门',
- imgUrl: '/imgs/index_page/transformer-icon12.png',
- },
- {
- label: '0元领水果',
- imgUrl: '/imgs/index_page/transformer-icon13.png',
- },
- {
- label: '天天赚现金',
- imgUrl: '/imgs/index_page/transformer-icon14.png',
- },
- {
- label: '冲吧饿小宝',
- imgUrl: '/imgs/index_page/transformer-icon15.png',
- },
- ],
- scrollBarInfoList: [
- {
- type: 'bean',
- badge: '赚豆',
- detail: `今天再下<span class="info-num">1</span>单赚<span class="info-num">400</span>吃货豆`,
- btn: '领任务',
- },
- {
- type: 'hongbao',
- badge: '红包',
- detail: `你有<span class="info-num">4</span>张总<span class="info-num">43.5</span>元红包即将到期`,
- btn: '去查看',
- },
- ],
- countdown: {
- time: 24 * 60 * 60 * 1000,
- goods: {
- imgUrl: '/imgs/index_page/count-down-p.png',
- name: '腊鸡腿菜饭 + 卤香干 + 冰红茶',
- price: 19.8,
- oldPrice: 28.9,
- },
- },
- activities: [
- '/imgs/index_page/activity/01.png',
- '/imgs/index_page/activity/02.png',
- '/imgs/index_page/activity/03.png',
- ]
- }
- }
- {
- "name": "mock-server",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1",
- "server": "nodemon delay 1000ms ./src/app.js"
- },
- "author": "",
- "license": "ISC",
- "dependencies": {
- "axios": "^1.5.0",
- "json-server": "^0.17.3"
- },
- "devDependencies": {
- "nodemon": "^3.0.1"
- }
- }

axios.get('/api/home_page').then(res=>{}).catch(err=>{});
在webpack.dev.js配置一下:
- devServer: {
- port: 8111,
- progress: true, // 显示打包的进度条
- contentBase: distPath, // 根目录
- open: true, // 自动打开浏览器
- compress: true, // 启动 gzip 压缩
- // 设置代理
- proxy: {
- // 将本地 /api/xxx 代理到 localhost:服务器端口号1/api/xxx
- '/api': 'http://localhost:8000',
-
- // 将本地 /api2/xxx 代理到 localhost:服务器端口号2/xxx
- '/api2': {
- target: 'http://localhost:8111',
- pathRewrite: {
- '/api2': ''
- }
- }
- }
- }
注意:
1) 因为逻辑简单且放在一个文件对于阅读逻辑代码, 更省事, 实际项目中应该分模块整理文件
2) connect模式未做成钩子文件, 读懂原理后可以自行改成钩子
- import { combineReducers, createStore } from "redux";
-
- // 将业务逻辑拆分到一个单独文件中,方便进行状态管理
- export interface StateProps {
- id: number;
- text: string;
- isFinished: boolean;
- }
- export interface ActionProps {
- type: string;
- [key: string]: any;
- }
- // 新增列表数据和改变数组数据
- export const reducer = (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 || [];
- }
- };
-
- export interface ContextProps {
- state: StateProps[];
- dispatch: React.Dispatch<ActionProps>;
- }
-
- const todos = reducer;
- const visibilityFilter = (state = 'SHOW_ALL', action) => {
- switch (action.type) {
- // 设置显示类型(所有、完成、未完成)
- case 'SET_VISIBILITY_FILTER':
- return action.filter
-
- // 默认是 SHOW_ALL
- default:
- return state
- }
- }
- export const combineStore = createStore(combineReducers({ todos, visibilityFilter }));
-
- // 不同类型的 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;
- }
- };
-
- export const mapStateToProps = (state) => {
- return {
- // 根据完成状态,筛选数据
- todoList: getVisibleTodos(state.todos, state.visibilityFilter),
- };
- };
-
- export 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,
- };
- };
- import { Provider } from "react-redux";
- import {combineStore} from './ProviderUtils';
-
- const ReduxProvider = (props) => {
- return <Provider store={combineStore}>{props.children}</Provider>;
- };
-
- export default ReduxProvider
- import ReduxProvider from "./ReduxProvider";
- import { TodoInput } from "./TodoInput";
- import { TodoList } from "./TodoList";
-
- // 父组件
- export const Todo = () => {
- return (
- <ReduxProvider>
- <TodoInput />
- <TodoList />
- </ReduxProvider>
- )
- }
- import { useState } from "react";
- import _ from "lodash";
- import { mapDispatchToProps, mapStateToProps } from "./ProviderUtils";
- 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 };
- import { mapDispatchToProps, mapStateToProps } from "./ProviderUtils";
- import _ from "lodash";
- import { connect } from "react-redux";
-
- // 孙子组件
- 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 };
- import { TodoItem } from "./TodoItem";
- import _ from "lodash";
- import { connect } from "react-redux";
- import { mapDispatchToProps, mapStateToProps } from "./ProviderUtils";
-
- 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 };
- const App:React.FC = ()=> {
- return <Todo />
- }
-
- export default App;
- 1) 引入import { combineReducers, createStore } from "redux";
-
- 2) 定义reducer方法们:
-
- // todos:新增,修改列表方法(返回列表数据, 否则返回state)
-
- 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 || [];
- }
- };
-
- // visibilityFilter: 筛选列表方法(返回筛选器, 否则返回state)
-
- const visibilityFilter = (state = 'SHOW_ALL', action) => {
- switch (action.type) {
- // 设置显示类型(所有、完成、未完成)
- case 'SET_VISIBILITY_FILTER':
- return action.filter
- default:
- return state
- }
- }
-
- 3) 得到combineStore
-
- export const combineStore = createStore(combineReducers({ todos, visibilityFilter }));
1) Provider从 "react-redux"获取;
2) combineStore从第1步获取
const ReduxProvider = (props) => {
return
};
export const Todo = () => {
return (
)
}
import { connect } from "react-redux";
const 子组件-新 = connect(mapStateToProps, mapDispatchToProps)(子组件);
export default 子组件-新;
注意: 因为子组件们使用了mapStateToProps, mapDispatchToProps, 可以直接写在子组件, 也可以写在公共文件
本文为了减少文件, 追加到ProviderUtils文件中
- // 不同类型的 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;
- }
- };
-
- export const mapStateToProps = (state) => {
- return {
- // 根据完成状态,筛选数据
- todoList: getVisibleTodos(state.todos, state.visibilityFilter),
- };
- };
-
- export 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,
- };
- };
6. 最后可以在子组件打印props查看:
1) props可以正常获取本身父组件传给它的数据和方法
2) props可以解构出mapStateToProps, mapDispatchToProps钩子return的数据变量和方法
以TodoItem组件为例:
- const TodoItem0 = (props) => {
- // 注意: todo是父组件直接传过来的数据, changeTodo是mapDispatchToProps钩子return出来的方法!!!
- 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 };
1) 添加数据后选中某些数据

2) 点击show finished显示被选中的那部分数据

3) 点击show not finish显示未被选中的那些数据

4) 点击show all展示所有数据
