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
{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 ;
}}
}
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 {children} ;
};
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 (
);
};
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 (
<>
checckbox-list:
{_.map(todoList, (item) => (
))}
>
);
};
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 (
{todo.text}
)
}
export default connect(mapStateTotProps, mapDispatchToProps)(TodoItem);
import React from "react";
import TodoInput from "./TodoInput";
import TodoList from "./TodoList";
// 父组件
const Todo = () => {
return (
<>
>
);
};
export default Todo;
import React from "react";
import Todo from './mockConnectProvider/Todo'
import ContextProvider from './mockConnectProvider/ContextProvider'
const App: React.FC = () => {
return (
);
};
export default App;
效果图如下: