- import React, { useState } from "react";
- import MyContext from "./MyContext";
- import _ from "lodash";
-
- // 模拟react-redux的 connect高阶函数
- const connect = (mapStateToProps, mapDispatchToProps) => {
- return (Component) => props => wrapper(Component, {mapStateToProps, mapDispatchToProps, ...props});
- };
-
- const wrapper = (Comp, props) => {
- const {mapStateToProps, mapDispatchToProps, ...rest} = props
-
- return <MyContext.Consumer>
- {store => {
- const dispatch = _.get(store, 'dispatch');
- const dispatchs = mapDispatchToProps(dispatch);
- // store.subscribe监听store.getState()获取最新的值
- const [states, setStates] = useState({})
- store.subscribe(() => {
- const state1 = store.getState();
- setStates(mapStateToProps(state1))
- });
-
- return <Comp {...{...states, ...dispatchs, ...rest}}/>;
- }}
- </MyContext.Consumer>
-
- }
-
- export default connect;
- import React from "react";
- import createContext from './createContext'
-
- const MyContext = createContext({});
-
- export default MyContext
- import React from "react";
-
- const createContext = ({}) => {
- let value = {};
-
- const Provider = (props) => {
- value = props.value;
-
- return <>{props.children}</>;
- };
-
- const Consumer = ({ children }: { children: any }) => {
- return <>{typeof children === "function" ? children(value) : children}</>;
- };
-
- return { Provider, Consumer };
- };
-
- export default createContext;
- // 新增列表数据和改变数组数据
- // 将业务逻辑拆分到一个单独文件中,方便进行状态管理
- import _ from 'lodash';
-
- export interface StateProps {
- id: number;
- text: string;
- isFinished: boolean;
- }
- export interface ActionProps {
- type: string;
- [key: string]: any;
- }
-
- interface IStateObjectProps {
- pickerArr: StateProps[];
- filterTag: 'SHOW_ALL'|'SHOW_FINISHED'|'SHOW_NOT_FINISH';
- dispatch: any;
- }
- const reducer = (state: IStateObjectProps, action: ActionProps) => {
- console.log(state, action, 'reducer');
- const pickerArr0 = _.get(state, 'pickerArr')||[];
- switch (action.type) {
- case "ADD":
- return {
- ...state,
- pickerArr: [...pickerArr0, _.get(action, 'todo')]
- };
- case "CHANGESTATUS":
- const pickerArr = _.map(pickerArr0, (item) => {
- if (item.id === action.id) {
- return Object.assign({}, item, { isFinished: !_.get(item, 'isFinished') });
- }
- return item;
- })||[];
- return {
- ...state,
- pickerArr,
- }
- case 'SET_VISIBILITY_FILTER':
- const filterTag = action.filterTag;
- return {
- ...state,
- filterTag,
- };
- default:
- return state || {};
- }
- };
-
- export default reducer
- import React from "react";
- import _ from "lodash";
- import store from "./store";
-
- // 不同类型的 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 mapStateTotProps = (state) => {
- // console.log(state, 'mapStateTotProps', store)
- return {
- todoList: getVisibleTodos(_.get(state, 'pickerArr')||[], _.get(state, 'filterTag'))|| [],
- }
- }
- import React from "react";
- import _ from "lodash";
- import { StateProps } from "./reducer";
-
- export const mapDispatchToProps = (dispatch) => {
- // console.log(dispatch, 'mapDispatchToProps============')
- // 筛选todo列表
- const onFilterTodoList = (filterTag) => {
- dispatch({ type: 'SET_VISIBILITY_FILTER', filterTag, });
- };
- const changeTodo = (id: number) => {
- dispatch({ type: "CHANGESTATUS", id: id });
- };
- // 添加todo
- const addTodo = (todo: StateProps) => {
- dispatch({ type: "ADD", todo });
- };
- const showAll = () => onFilterTodoList("SHOW_ALL");
- const showFinished = () => onFilterTodoList("SHOW_FINISHED");
- const showNotFinish = () => onFilterTodoList("SHOW_NOT_FINISH");
-
- return {
- changeTodo,
- addTodo,
- showAll,
- showFinished,
- showNotFinish,
- };
- }
由mapStateToProps文件和mapDispatchToProps文件可知, 我们需要想办法获取最新的state, 和通用的dispatch方法, 也就是以下所说的store文件里面的默认导出对象:
- import React from 'react';
- import reducer from './reducer'
-
- function createStore(reducer) {
- let state = null;
- const listeners = [];
- const subscribe = (fn) => listeners.push(fn);
- const getState = () => state;
- const dispatch = (action) => {
- const state1 = reducer(state, action);
- state = state1
- // 因为是在获取到最新的state的值之后有执行的监听回调, 所以使用store.subscribe可以监听到最新的state的值!!!
- listeners.forEach((fn) => fn());
- return state
- }
- // dispatch({})
- return { getState, dispatch, subscribe, reducer }
- }
-
- const store = createStore(reducer)
-
- console.log(store.getState(), 'oldState======')
- store.subscribe(() => {
- const newState = store.getState()
- // 数据可能变化,需要监听最新的
- console.log(newState, 'newState====');
- })
-
-
- export default store;
- import React from "react";
- import MyContext from "./MyContext";
- import store from "./store";
- import _ from "lodash";
-
- // 父组件
- const ContextProvider = ({ children }) => {
- return <MyContext.Provider value={store}>{children}MyContext.Provider>;
- };
-
- export default ContextProvider;
- import React, { useState } from "react";
- import "./TodoInput.scss";
- import connect from './connect';
- import { mapStateTotProps } from "./mapStateToProps";
- import { mapDispatchToProps } from "./mapDispatchToProps";
-
- // 子组件
- const TodoInput = (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 onClick={handleAddTodo}>+添加</button>
- <button onClick={showAll}>show all</button>
- <button onClick={showFinished}>show finished</button>
- <button onClick={showNotFinish}>show not finish</button>
- </div>
- );
- };
-
- export default connect(mapStateTotProps, mapDispatchToProps)(TodoInput);
- import React from "react";
- import TodoItem from "./TodoItem";
- import _ from "lodash";
- import connect from "./connect";
- import { mapStateTotProps } from "./mapStateToProps";
- import { mapDispatchToProps } from "./mapDispatchToProps";
-
- const TodoList = (props) => {
- const { todoList } = props;
-
- return (
- <>
- <p>checckbox-list: </p>
- <div className="todo-list">
- {_.map(todoList, (item) => (
- <TodoItem key={_.get(item, "id")} todo={item || {}} />
- ))}
- </div>
- <hr />
- </>
- );
- };
-
- export default connect(mapStateTotProps, mapDispatchToProps)(TodoList);
- import _ from 'lodash';
- import React from "react";
- import connect from './connect';
- import { mapStateTotProps } from "./mapStateToProps";
- import { mapDispatchToProps } from "./mapDispatchToProps";
-
- // 孙子组件
- const TodoItem = (props: any) => {
- 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: _.get(todo, 'isFinished') ? 'line-through' : 'none' }}>{todo.text}</span>
- </div>
- )
- }
-
- export default connect(mapStateTotProps, mapDispatchToProps)(TodoItem);
- import React from "react";
- import TodoInput from "./TodoInput";
- import TodoList from "./TodoList";
-
- // 父组件
- const Todo = () => {
- return (
- <>
- <TodoInput />
- <TodoList />
- </>
- );
- };
- export default Todo;
- import React from "react";
- import Todo from './mockConnectProvider/Todo'
- import ContextProvider from './mockConnectProvider/ContextProvider'
-
- const App: React.FC = () => {
- return (
- <ContextProvider>
- <Todo />
- </ContextProvider>
- );
- };
-
- export default App;
效果图如下:

- import React from "react";
- import Todo from "./mockConnectProvider/Todo";
- import { RecoilRoot } from "recoil";
-
- const App: React.FC = () => {
- return (
- <RecoilRoot>
- <Todo />
- </RecoilRoot>
- );
- };
-
- export default App;
- import React from "react";
- import TodoInput from "./TodoInput";
- import TodoList from "./TodoList";
- import ContextProvider from "./ContextProvider";
-
- // 父组件
- const Todo = () => {
- return (
- <ContextProvider>
- <TodoInput />
- <TodoList />
- </ContextProvider>
- );
- };
- export default Todo;
- import React from "react";
- import MyContext from "./MyContext";
- import _ from "lodash";
- import { atom, useRecoilState } from "recoil";
-
- const connectState1 = atom({
- key: "connect-state1",
- default: {},
- });
- // 模拟react-redux的 connect高阶函数
- const connect = (mapStateToProps, mapDispatchToProps) => {
- return (Component) => (props) =>
- wrapper(Component, { mapStateToProps, mapDispatchToProps, ...props });
- };
-
- const useReducer = (store) => {
- const [state, setState] = useRecoilState(connectState1);
-
- const dispatch = (action) => {
- const state1 = store.dispatch(action);
- setState((state0: any) => ({
- ...state0,
- ...state1,
- }));
- };
- return [state, dispatch];
- };
-
- const wrapper = (Comp, props) => {
- const { mapStateToProps, mapDispatchToProps, ...rest } = props;
-
- return (
- <MyContext.Consumer>
- {(store) => {
- const [state, dispatch] = useReducer(store);
- const dispatchs = mapDispatchToProps(dispatch);
- let states1 = mapStateToProps(state);
-
- return <Comp {...{ ...states1, ...dispatchs, ...rest }} />;
- }}
- </MyContext.Consumer>
- );
- };
-
- export default connect;
原理:
1) RecoilRoot标签类似redux的Provider标签, 有了它, 方便全局组件通信
2) useRecoilState钩子可以设置同源下的全局变量, 自然一处修改了, 所有组件都能触发更新
- import React from "react";
- import Todo from "./mockConnectProvider/Todo";
-
- const App: React.FC = () => {
- return (
- <>
- <Todo />
- </>
- );
- };
-
- export default App;
- import React from "react";
- import TodoInput from "./TodoInput";
- import TodoList from "./TodoList";
- import ContextProvider from "./ContextProvider";
-
- // 父组件
- const Todo = () => {
- return (
- <ContextProvider>
- <TodoInput />
- <TodoList />
- </ContextProvider>
- );
- };
- export default Todo;
- import React from "react";
-
- const MyContext = React.createContext({});
-
- export default MyContext
- import React, { useContext } from "react";
- import MyContext from "./MyContext";
- import _ from "lodash";
- import reducer from "./reducer";
-
- // 父组件
- const ContextProvider = ({ children }) => {
- const context:any = useContext(MyContext);
- const [state, dispatch] = React.useReducer(reducer, context);
-
- return <MyContext.Provider value={{getState:() => state, dispatch}}>{children}</MyContext.Provider>;
- };
-
- export default ContextProvider;
- import React from "react";
- import MyContext from "./MyContext";
- import _ from "lodash";
-
- // 模拟react-redux的 connect高阶函数
- const connect = (mapStateToProps, mapDispatchToProps) => {
- return (Component) => (props) =>
- wrapper(Component, { mapStateToProps, mapDispatchToProps, ...props });
- };
-
- const wrapper = (Comp, props) => {
- const { mapStateToProps, mapDispatchToProps, ...rest } = props;
-
- return (
- <MyContext.Consumer>
- {(store) => {
- const dispatchs = mapDispatchToProps(_.get(store, 'dispatch'));
- let states1 = mapStateToProps(_.get(store, 'getState') ? _.get(store, 'getState')(): {});
-
- return <Comp {...{ ...states1, ...dispatchs, ...rest }} />;
- }}
- </MyContext.Consumer>
- );
- };
-
- export default connect;
6. 其他需要的组件文件从一, 二中查找,
注意: 此种方法不需要store文件了