react的状态管理简单钩子方法

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 />就行;

效果图如下:

点击添加按钮,新增一列,点击多选框(选中)中划线一行,取消选中该行就恢复正常

相关推荐
前端李二牛几秒前
异步任务并发控制
前端·javascript
你也向往长安城吗21 分钟前
推荐一个三维导航库:three-pathfinding-3d
javascript·算法
karrigan31 分钟前
async/await 的优雅外衣下:Generator 的核心原理与 JavaScript 执行引擎的精细管理
javascript
wycode39 分钟前
Vue2实践(3)之用component做一个动态表单(二)
前端·javascript·vue.js
wycode2 小时前
Vue2实践(2)之用component做一个动态表单(一)
前端·javascript·vue.js
第七种黄昏2 小时前
Vue3 中的 ref、模板引用和 defineExpose 详解
前端·javascript·vue.js
我是哈哈hh2 小时前
【Node.js】ECMAScript标准 以及 npm安装
开发语言·前端·javascript·node.js
张元清3 小时前
电商 Feeds 流缓存策略:Temu vs 拼多多的技术选择
前端·javascript·面试
晴空雨3 小时前
React 合成事件原理:从事件委托到 React 17 的重大改进
前端·react.js
pepedd8643 小时前
浅谈js拷贝问题-解决拷贝数据难题
前端·javascript·trae