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

效果图如下:

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

相关推荐
FungLeo5 分钟前
成为全栈·Vue管理后台篇·仪表盘不是几张卡片:组合统计接口与角色视图
前端·javascript·vue.js·rbac·仪表盘·管理后台·tanstack query
程序员大阳7 分钟前
HTML+CSS+JS对话式实战(7)-学生端活动报名功能开发
javascript·css·html·活动报名
西安小哥1 小时前
做 Agent 写到第三个小时,我开始给它算账
javascript
西安小哥1 小时前
让大模型操作浏览器跑了两周,我发现瓶颈根本不在模型
javascript
用户298698530141 小时前
用 Python 自动化把 JavaScript 代码转换为 Word 文档
javascript·python·api
学以智用1 小时前
正则表达式完整参考手册(JavaScript 版,兼容绝大多数语言)
javascript
北城笑笑1 小时前
Vue 109 ,从零搭建 Vue3 + Electron 工程:生态、安全桥接与打包选型( Vue + Electron )
前端·javascript·vue.js·安全·electron·vue
Highcharts.js2 小时前
Highcharts智能数据分析平台Orbit 多语言配置技术文档
java·前端·javascript·highcharts·orbit·智能数据分析·设置文档
非优秀程序员13 小时前
第07章 孙德良的阳谋|《互联网产品恩仇录》
javascript·后端
程序员大阳16 小时前
HTML+CSS+JS对话式实战(5)-活动管理页之查看报名名单的实现
javascript·css·html·查看报名名单