【react18】如何使用useReducer和useContext来实现一个todoList功能

重点知识点就是使用useReducer来攻坚小型的公共状态管理,useImmerReducer来实现数据的不可变

实现效果

实现代码

  • 项目工程结构
  • App.js文件
js 复制代码
import logo from "./logo.svg";
import "./App.css";
import TodoLists from "./comps/TodoLists";
import AddItem from "./comps/AddItem";
import todoListsContext from "./comps/todolistContext";
// import { useReducer } from "react";
import { useImmerReducer } from "use-immer";
import FooterCompo from "./comps/FooterCompo";

// function todoListsReducer(state, action) {
//   switch (action.type) {
//     case "CHANGE_INPUT_VALUE":
//       return {
//         ...state,
//         inputValue: action.payload,
//       };
//       break;
//     case "ADD_ITEM":
//       return { ...state, todos: [...state.todos, action.payload] };
//       break;
//     default:
//       return state;
//   }
// }
function todoListsReducer(state, action) {
  switch (action.type) {
    case "CHANGE_INPUT_VALUE":
      state.inputValue = action.payload;
      return state;

    case "ADD_ITEM":
      state.todos = [...state.todos, action.payload];
      return state;

    case "DONE_ITEM":
      state.todos = state.todos.map((todo) => {
        console.log(action, "done");
        if (todo.id === action.payload.id) {
          return { ...todo, completed: !action.payload.completed };
        }
        return todo;
      });
      return state;

    case "DELETE_ITEM":
      state.todos = state.todos.filter((todo) => todo.id !== action.payload);
      return state;

    default:
      return state;
  }
}

function App() {
  // const [store, dispatch] = useReducer(todoListsReducer, {
  //   inputValue: "",
  //   todos: [],
  // });
  const [store, dispatch] = useImmerReducer(todoListsReducer, {
    inputValue: "",
    todos: [],
  });
  return (
    <div className="App">
      <h1>TodoLists</h1>
      <todoListsContext.Provider value={store}>
        <AddItem dispatch={dispatch} />
        <TodoLists dispatch={dispatch} />
        <FooterCompo />
      </todoListsContext.Provider>
    </div>
  );
}

export default App;
  • AddItem组件
js 复制代码
import { useContext } from "react";
import todoListsContext from "./todolistContext";
import { v4 as uuid } from "uuid";

function AddItem({ dispatch }) {
  const data = useContext(todoListsContext);
  const handleChangeInputValue = (e) => {
    dispatch({
      type: "CHANGE_INPUT_VALUE",
      payload: e.target.value,
    });
  };
  const handleAddItem = () => {
    if (!data.inputValue) {
      return alert("Please enter a valid item");
    }
    dispatch({
      type: "ADD_ITEM",
      payload: {
        id: uuid(),
        title: data.inputValue,
        completed: false,
      },
    });
    dispatch({
      type: "CHANGE_INPUT_VALUE",
      payload: "",
    });
  };
  return (
    <div>
      <input
        type="text"
        value={data.inputValue}
        placeholder="Enter item name"
        onChange={handleChangeInputValue}
      ></input>
      <button onClick={handleAddItem}>add list</button>
    </div>
  );
}

export default AddItem;
  • FooterCompo组件
js 复制代码
import todoListsContext from "./todolistContext";
import { useContext } from "react";
import { useMemo } from "react";
function FooterCompo() {
  const { todos } = useContext(todoListsContext);
  const completedCount = useMemo(
    () => todos.filter((e) => e.completed).length,
    [todos]
  );
  const remain = useMemo(
    () => todos.length - completedCount,
    [todos, completedCount]
  );
  return (
    <div>
      <span>all: {todos.length}</span> <span>completed: {completedCount}</span>{" "}
      <span>todo: {remain}</span>
    </div>
  );
}

export default FooterCompo;
  • 使用createContext来创建公共状态
js 复制代码
import { createContext } from "react";

const todoListsContext = createContext({});

export default todoListsContext;
  • UI美化
css 复制代码
.completed {
    text-decoration: line-through;
    color: gray;
}
.todo-list{
  cursor: pointer;
}

.todo-text{
  margin: auto 10px auto 4px;
}
.del-btn{
  cursor: pointer;
  color: gray;
}
.todo-item{
  text-align: left;

}
  • TodoLists组件
js 复制代码
import { useContext } from "react";
import todoListsContext from "./todolistContext";
import classNames from "classnames";
import "./todoLists.css";

function TodoLists({ dispatch }) {
  const data = useContext(todoListsContext);
  const handleDoneItem = (item) => {
    dispatch({ type: "DONE_ITEM", payload: item });
  };
  const handleDelItem = (id) => {
    dispatch({ type: "DELETE_ITEM", payload: id });
  };
  return (
    <>
      <ul>
        {data.todos.map((todoList) => {
          return (
            <li key={todoList.id} className="todo-item">
              <span
                className={classNames({
                  completed: todoList.completed,
                  "todo-list": true,
                })}
              >
                <input
                  type="checkbox"
                  checked={todoList.completed}
                  onChange={() => handleDoneItem(todoList)}
                />
                <span className="todo-text">{todoList.title}</span>
              </span>
              <span
                className={classNames({
                  // completed: todoList.completed,
                  "del-btn": todoList.completed,
                })}
                onClick={() => handleDelItem(todoList.id)}
              >
                del
              </span>
            </li>
          );
        })}
      </ul>
    </>
  );
}
export default TodoLists;
相关推荐
N***738520 分钟前
前端路由权限动态更新,Vue与React实现
前端·vue.js·react.js
Sailing1 小时前
🔥 React 高频 useEffect 导致页面崩溃的真实案例:从根因排查到彻底优化
前端·react.js·面试
o***Z4481 小时前
前端组件表单验证,React Hook Form与VeeValidate
前端·react.js·前端框架
小霖家的混江龙3 小时前
巧用辅助线,轻松实现类拼多多的 Tab 吸顶效果
前端·javascript·react.js
A***27953 小时前
前端路由管理最佳实践,React Router
前端·react.js·前端框架
zhenryx11 小时前
React Native 自定义 ScrollView 滚动条:开箱即用的 IndicatorScrollView(附源码示例)
javascript·react native·react.js·typescript
Xeon_CC14 小时前
在react-app-rewired工程项目中,调试AntVG6库源码包。
前端·react.js·前端框架
码上成长14 小时前
React 18 并发特性:useTransition 和 useDeferredValue 动画级解释
javascript·react.js·ecmascript
G***T69115 小时前
React性能优化实战,避免不必要的重渲染
前端·javascript·react.js
菜鸟‍1 天前
【前端学习】React学习【万字总结】
前端·学习·react.js