目录
- // 新增列表数据和改变数组数据
- // 将业务逻辑拆分到一个单独文件中,方便进行状态管理
- 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, 'reducer11111');
- const pickerArr0 = _.get(state, 'pickerArr')||[];
- switch (_.get(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 reducer from './reducer'
-
- // compose执行顺序就是从后往前
- const compose = (...funcs) => {
- if (funcs.length === 0) return arg => arg
- return funcs.reduce((v, cur) => (...args) => (v(cur(...args))))
- }
-
- function applyMiddleware(...args) {
- // 将中间件们变成一个数组
- const middlewares = Array.from({ length: args.length }, (_, _key) => args[_key]);
- return function (createStore) {
- return function () {
- const store = createStore.apply(void 0, arguments);
- const middlewareAPI = {
- getState: store.getState,
- dispatch: store.dispatch,
- };
- // map遍历中间件, 执行监听器函数, 形成新数组
- const chain = middlewares.map((middleware) => middleware(middlewareAPI));
- // 展开中间件,调整执行顺序,并传入store.dispatch
- const dispatch = compose(...chain)(store.dispatch);
- // 返回需要的存储数据(将dispatch合并进store对象)
- return {
- ...store,
- dispatch,
- };
- };
- };
- }
-
- function legacy_createStore(reducer, preloadedState) {
- let state = preloadedState || 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
- }
-
- return { getState, dispatch, subscribe }
- }
-
- function createStore(reducer, preloadedState, enhancer) {
- if (typeof preloadedState === 'function') {
- return preloadedState(legacy_createStore)(reducer)
- }
- if (typeof enhancer === 'function') {
- return enhancer(legacy_createStore)(reducer, preloadedState)
- }
- return legacy_createStore(reducer, preloadedState)
- }
-
- function createThunkMiddleware(extraArgument) {
- return ({ dispatch, getState }) => next => action => {
- if (typeof action === 'function') {
- return action(dispatch, getState, extraArgument)
- }
- return next(action)
- }
- }
-
- const thunk = createThunkMiddleware('xxxxxx');
- const store = applyMiddleware(thunk)(createStore)(reducer);
- // 或者
- // const store = createStore(reducer, applyMiddleware(thunk));
- // 或者
- // const store = createStore(reducer);
-
- console.log(store, 'oldState======')
- store.subscribe(() => {
- const newState = store.getState()
- // 数据可能变化,需要监听最新的
- console.log(newState, 'newState====');
- })
-
- export default store;
- import React from "react";
-
- const MyContext = React.createContext({});
-
- export default MyContext
- import React, {ReactNode, memo} from "react";
-
- // 已经使用了React.createContext, 这个可以忽略, 只是为了展示createContext功能的简单代码
- const createContext = ({}) => {
- let value = {};
-
- const Provider = memo((props: {
- children: ReactNode;
- value:{
- dispatch: (arg1:any)=>void;
- getState:() => any;
- };
- }) => {
- value = props.value;
-
- return <>{props.children}</>;
- });
-
- const Consumer = memo(({ children }: { children: any }) => {
- return <>{typeof children === "function" ? children(value) : children}</>;
- });
-
- return { Provider, Consumer };
- };
-
- export default createContext;
- import React, { useState } from "react";
- import MyContext from "./MyContext";
- import _ from "lodash";
- import store from "./store";
-
- const useReducer = (state0, dispatch0) => {
- const [state, dispatch] = useState(state0);
- const dispatch1 = (action) => {
- dispatch0(action);
- dispatch(store.getState());
- };
- return [state, dispatch1]
- }
-
- // 父组件
- const ContextProvider = ({ children }) => {
- const [state, dispatch] = useReducer(store.getState(), store.dispatch);
-
- 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;
- 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, { useEffect } from "react";
- import TodoItem from "./TodoItem";
- import _ from "lodash";
- import connect from "./connect";
- import { mapStateTotProps } from "./mapStateToProps";
- import { mapDispatchToProps } from "./mapDispatchToProps";
- import styles from './TodoList.scss'
-
- const TodoList = (props) => {
- const { todoList } = props;
- console.log(styles, 'TodoList-styles', props)
-
- return (
- <>
- <p className={styles.title}>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, { useState } from "react";
- import connect from './connect';
- import { mapStateTotProps } from "./mapStateToProps";
- import { mapDispatchToProps } from "./mapDispatchToProps";
- import styles from './TodoInput.scss'
-
- // 子组件
- const TodoInput = (props) => {
- // console.log(styles, 'styles', 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={styles["todo-input"]}>
- <input
- type="text"
- placeholder="请输入代办事项"
- onChange={handleChangeText}
- value={text}
- className="aaa"
- />
- <button className={styles.btn} onClick={handleAddTodo}>+添加</button>
- <button className={styles.btn} onClick={showAll}>show all</button>
- <button className={styles.btn} onClick={showFinished}>show finished</button>
- <button className={styles.btn} onClick={showNotFinish}>show not finish</button>
- </div>
- );
- };
-
- export default connect(mapStateTotProps, mapDispatchToProps)(TodoInput);