1.recoil
useProvider文件:
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 };
}
Todo组件:
import { TodoInput } from "./TodoInput";
import { TodoList } from "./TodoList";
// 父组件
export const Todo = () => {
return (
<>
<TodoInput />
<TodoList />
</>
)
}
TodoInput组件:
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>
)
}
TodoItem组件:
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>
)
}
TodoList组件:
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>
)
}
然后在App组件引入Todo组件<Todo />
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;
2.context状态管理:
useProvider文件:
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 };
}
ContextProvider文件:
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;
Todo组件:
import ContextProvider from "./ContextProvider";
import { TodoInput } from "./TodoInput";
import { TodoList } from "./TodoList";
// 父组件
export const Todo = () => {
return (
<ContextProvider>
<TodoInput />
<TodoList />
</ContextProvider>
)
}
TodoInput 和TodoList 组件不变
使用Todo组件直接使用<Todo />就行;
效果图如下:
点击添加按钮,新增一列,点击多选框(选中)中划线一行,取消选中该行就恢复正常