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

效果图如下:

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

相关推荐
隔壁小邓16 分钟前
前端Vue项目打包部署实战教程
前端·javascript·vue.js
TON_G-T1 小时前
javascript中 Iframe 处理多端通信、鉴权
开发语言·前端·javascript
周淳APP1 小时前
【JS之闭包防抖节流,this指向,原型&原型链,数据类型,深浅拷贝】简单梳理啦!
开发语言·前端·javascript·ecmascript
kyriewen1 小时前
console.log 骗了我一整个通宵:原来它才是时间旅行者
前端·javascript·chrome
冴羽1 小时前
在浏览器控制台调试的 6 个秘密技巧
前端·javascript·chrome
前端Hardy1 小时前
别再手动调 Prompt 了!这款开源神器让 AI 输出质量提升 300%,支持 Claude、GPT、Gemini,还免费开源!
前端·javascript·面试
敲代码的约德尔人1 小时前
React 性能优化完全指南:从渲染机制到实战技巧
react.js
许留山1 小时前
前端 PDF 导出:从文件流下载到自动分页
前端·react.js
敲代码的约德尔人1 小时前
ES2025 JavaScript 新特性预览
javascript
angerdream1 小时前
最新版vue3+TypeScript开发入门到实战教程之watch详解
javascript·vue.js