美文网首页
useReducer 实现todoList ts规范书写

useReducer 实现todoList ts规范书写

作者: 薛定谔的程序 | 来源:发表于2021-02-08 20:26 被阅读0次

    优化 展示列表和输入组件应该没有自己的逻辑,应该完全可控,方法都是父组件传入

      const handleAddTodo = useCallback((todo: Todo) => {
        addTodo(todo)(dispatch);
      }, []);
    
      const handleRemoveList = useCallback(
        (id: ID) => () => {
          removeTodo(id)(dispatch);
        },
        []
      );
    
      const handleToggleListStatus = useCallback(
        (id: ID) => () => {
          toggleTodoListStatus(id)(dispatch);
        },
        []
      );
    
    <Input onAddTodo={handleAddTodo} />
    <List
         todoList={todoList}
         onRemoveList={handleRemoveList}
         onToggleListStatus={handleToggleListStatus}
       />
    

    typing/index.ts

    export type Content = string;
    export type ID = string;
    export interface Todo {
      id: ID;
      content: Content;
      complete: boolean;
    }
    
    export type TodoList = Array<Todo>;
    
    export enum Actions {
      ADD_TODO = "ADD_TODO",
      REMOVE_TODO = "REMOVE_TODO",
      TOGGLE_TODO_STATUS = "TOGGLE_TODO_STATUS",
    }
    export interface IAction {
      type: Actions;
      payload: ID | Todo;
    }
    
    

    action.ts

    import { Dispatch } from "react";
    import { Actions, Todo, ID } from "./typing";
    // add
    export interface IAddTodoAction {
      type: Actions;
      payload: Todo;
    }
    
    const addTodoAction = (todo: Todo): IAddTodoAction => ({
      type: Actions.ADD_TODO,
      payload: todo,
    });
    
    export const addTodo = (todo: Todo) => (dispatch: Dispatch<IAddTodoAction>) => {
      dispatch(addTodoAction(todo));
    };
    // remove
    export interface IRemoveTodoAction {
      type: Actions;
      payload: ID;
    }
    
    const removeTodoAction = (ID: ID): IRemoveTodoAction => ({
      type: Actions.REMOVE_TODO,
      payload: ID,
    });
    
    export const removeTodo = (ID: ID) => (
      dispatch: Dispatch<IRemoveTodoAction>
    ) => {
      dispatch(removeTodoAction(ID));
    };
    // toggle
    export interface IToggleTodoStatusAction {
      type: Actions;
      payload: ID;
    }
    
    const toggleTodoStatusAction = (ID: ID): IToggleTodoStatusAction => ({
      type: Actions.TOGGLE_TODO_STATUS,
      payload: ID,
    });
    
    export const toggleTodoStatus = (ID: ID) => (
      dispatch: Dispatch<IToggleTodoStatusAction>
    ) => {
      dispatch(toggleTodoStatusAction(ID));
    };
    

    reducer.ts

    import { TodoList, IAction, Actions, Todo, ID } from "./typing/index";
    
    export const reducer = (state: TodoList, action: IAction): TodoList => {
      const { type, payload } = action;
    
      switch (type) {
        case Actions.ADD_TODO:
          return [...state, payload as Todo];
        case Actions.REMOVE_TODO:
          return state.filter((todo: Todo) => todo.id !== (payload as ID));
        case Actions.TOGGLE_TODO_STATUS:
          return state.map((todo: Todo) => {
            if (todo.id === payload) {
              todo.complete = !todo.complete;
            }
            return todo;
          });
        default:
          return state;
      }
    };
    
    

    index.tsx

    import React, {
      FC,
      ReactElement,
      useReducer,
      useEffect,
      useCallback,
    } from "react";
    import { ContentContainer } from "../../constants/LayoutStyled";
    import { Typography } from "@material-ui/core";
    import Input from "./Input";
    import List from "./List";
    import { reducer } from "./reducer";
    
    const initializer = () => JSON.parse(localStorage.getItem("todoList") || "[]");
    
    const TodoList: FC = (): ReactElement => {
      const [todoList, dispatch] = useReducer(reducer, undefined, initializer);
    
      const saveLocalStorage = useCallback(
        (todoList) => () => {
          localStorage.setItem("todoList", JSON.stringify(todoList));
        },
        []
      );
    
      // eslint-disable-next-line react-hooks/exhaustive-deps
      useEffect(saveLocalStorage(todoList), [todoList]);
    
      return (
        <ContentContainer>
          <Typography variant="caption">ToDo List</Typography>
          <Input dispatch={dispatch} />
          <List todoList={todoList} dispatch={dispatch} />
        </ContentContainer>
      );
    };
    export default TodoList;
    

    input.tsx

    import React, { Dispatch, FC, ReactElement, useCallback, useRef } from "react";
    import { TextField } from "../../components/UI/Input";
    import { Button } from "../../components/UI/Button";
    import { Grid } from "@material-ui/core";
    import { addTodo, IAddTodoAction } from "./action";
    import { v1 as UUIDV1 } from "uuid";
    interface IProps {
      dispatch: Dispatch<IAddTodoAction>;
    }
    
    const Input: FC<IProps> = ({ dispatch }): ReactElement => {
      const input = useRef<HTMLInputElement>(null);
    
      const handleAddTodo = useCallback((): void => {
        const content = input!.current!.value;
        addTodo({ id: UUIDV1(), content, complete: false })(dispatch);
        input!.current!.value = "";
      }, [dispatch]);
    
      return (
        <Grid container spacing={2}>
          <Grid container item xs={12} sm={3}>
            <TextField inputRef={input} label="TODO" flex={1} />
          </Grid>
          <Grid
            container
            item
            xs={12}
            sm={3}
            alignItems="flex-end"
            justify="flex-start"
          >
            <Button
              onClick={handleAddTodo}
              width="100px"
              variant="outlined"
              color="primary"
            >
              ADD
            </Button>
          </Grid>
        </Grid>
      );
    };
    
    export default Input;
    
    

    list/index.tsx

    import React, { FC, ReactElement, useCallback, Dispatch } from "react";
    import { ID, Todo, TodoList } from "../typing";
    import { List as MaterialList, Grid, Typography } from "@material-ui/core";
    import {
      IRemoveTodoAction,
      IToggleTodoStatusAction,
      removeTodo,
      toggleTodoStatus,
    } from "../action";
    import ListItem from "./ListItem";
    
    interface IProps {
      todoList: TodoList;
      dispatch: Dispatch<IRemoveTodoAction | IToggleTodoStatusAction>;
    }
    
    const List: FC<IProps> = ({ todoList, dispatch }): ReactElement => {
      const handleToggleTodoStatus = useCallback(
        (Id: ID) => () => toggleTodoStatus(Id)(dispatch),
        [dispatch]
      );
    
      const handleRemoveTodo = useCallback(
        (Id: ID) => () => removeTodo(Id)(dispatch),
        [dispatch]
      );
    
      const renderTodoItem = useCallback(
        (todo: Todo) => (
          <ListItem
            key={todo.id}
            todo={todo}
            handleToggleTodoStatus={handleToggleTodoStatus}
            handleRemoveTodo={handleRemoveTodo}
          />
        ),
        [handleToggleTodoStatus, handleRemoveTodo]
      );
      if (todoList.length) {
        return (
          <Grid>
            <Grid item sm={6}>
              <MaterialList>{todoList.map(renderTodoItem)}</MaterialList>
            </Grid>
          </Grid>
        );
      }
      return <Typography color="textPrimary">not data</Typography>;
    };
    
    export default List;
    

    List/ListItem

    import {
      Checkbox,
      ListItemIcon,
      ListItemText,
      ListItem as MaterialListItem,
    } from "@material-ui/core";
    import { IndeterminateCheckBox } from "@material-ui/icons";
    import React, { FC, ReactElement } from "react";
    import { Todo, ID } from "../typing";
    
    interface ITodoListItem {
      todo: Todo;
      handleToggleTodoStatus: (id: ID) => () => void;
      handleRemoveTodo: (id: ID) => () => void;
    }
    
    const ListItem: FC<ITodoListItem> = ({
      todo: { id, content, complete },
      handleRemoveTodo,
      handleToggleTodoStatus,
    }: ITodoListItem): ReactElement => (
      <MaterialListItem divider button>
        <ListItemIcon>
          <Checkbox
            checked={complete}
            color="primary"
            onChange={handleToggleTodoStatus(id)}
          />
        </ListItemIcon>
        <ListItemText primary={content} />
        <ListItemIcon>
          <IndeterminateCheckBox onClick={handleRemoveTodo(id)} />
        </ListItemIcon>
      </MaterialListItem>
    );
    
    export default ListItem;
    
    
    在这里插入图片描述

    相关文章

      网友评论

          本文标题:useReducer 实现todoList ts规范书写

          本文链接:https://www.haomeiwen.com/subject/plufxltx.html