美文网首页
Recoil学习(二)---实现TodoList

Recoil学习(二)---实现TodoList

作者: koala949 | 来源:发表于2020-06-14 15:33 被阅读0次

    官方文档的todolist示例~

    1. 安装

    npm install recoil 或 yarn add recoil

    2. 具体实现

    todoList是一个对象数组,将todoListState作为一个原子, 初始值为空数组。
    数组每一项对象属性有{id,text, isComplete}

    const todoListState = atom({
       key : 'todoListState',
       default: [],
    })
    

    使用useRecoilValue()钩子将todoListState运用于 TodoList组件中。

    function TodoList() {
      const todoList = useRecoilValue(todoListState);
    
      return (
        <>
          {/* <TodoListStats /> */}
          {/* <TodoListFilters /> */}
          <TodoItemCreator />
    
          {todoList.map((todoItem) => (
            <TodoItem key={todoItem.id} item={todoItem} />
          ))}
        </>
      );
    }
    (被注释的组件在下文实现~)
    

    要创建一个新的todo项,我们需要使用setter函数去更新todoListState的内容----在 TodoItemCreator 组件中使用useSetRecoilState()钩子。

    function TodoItemCreator(){
      const [inputValue, setInputValue] = useState('');
      const setTodoList = useSetRecoilState(todoListState);
    
      const  addItem = () => {
         setTodoList((oldTodoList) => [
            ...oldTodoList,
           {
              id: uuid(),
              text: inputValue,
              isComplete: false, 
           }
         ]);
         setInputValue('')
      }
     const onChange = ({target: {value}}) => {
        setInputValue(value);
      };
    return (
        <div>
          <input type="text" value={inputValue} onChange={onChange} />
          <button onClick={addItem}>Add</button>
        </div>
      );
    }
    

    todoItem 组件将展示todoListState中所有的值。 我们使用 useRecoilState() 获取值,并且使用setter函数去更新todoList的值,更新某项的状态,或者删除某项。

    function TodoItem({item}) {
      const [todoList, setTodoList] = useRecoilState(todoListState);
      const index = todoList.findIndex((listItem) => listItem === item);
    
      const editItemText = ({target: {value}}) => {
        const newList = replaceItemAtIndex(todoList, index, {
          ...item,
          text: value,
        });
    
        setTodoList(newList);
      };
    
      const toggleItemCompletion = () => {
        const newList = replaceItemAtIndex(todoList, index, {
          ...item,
          isComplete: !item.isComplete,
        });
    
        setTodoList(newList);
      };
    
      const deleteItem = () => {
        const newList = removeItemAtIndex(todoList, index);
    
        setTodoList(newList);
      };
    
      return (
        <div>
          <input type="text" value={item.text} onChange={editItemText} />
          <input
            type="checkbox"
            checked={item.isComplete}
            onChange={toggleItemCompletion}
          />
          <button onClick={deleteItem}>X</button>
        </div>
      );
    }
    
    function replaceItemAtIndex(arr, index, newValue) {
      return [...arr.slice(0, index), newValue, ...arr.slice(index + 1)];
    }
    
    function removeItemAtIndex(arr, index) {
      return [...arr.slice(0, index), ...arr.slice(index + 1)];
    }
    

    到此 一个基础的增删改的todoList就实现啦。

    之后我们使用selector来呈现基于todoList数组的衍生数据,通过函数方法获取及呈现与todoList相关的数据。如:

    • 根据某个条件过滤出的数据
    • 通过计算获取数组的一些属性,如completed的item数量, 或者completed item 所占的百分比。
    1. TodoListFilters
      我们将过滤条件设置为一个原子。原子的值范围为: "Show All", "Show Completed", "Show Uncompleted"。默认值为‘show all’.
    const todoListFilterState = atom({
      key: 'todoListFilterState',
      default: 'Show All',
    });
    

    我们使用todoListFilterStatetodoListState, 构建filteredTodoListState selector 来衍生出过滤的list数据。

    const filteredTodoListState = selector({
      key: 'filteredTodoListState',
      get: ({get}) => {
        const filter = get(todoListFilterState);
        const list = get(todoListState);
    
        switch (filter) {
          case 'Show Completed':
            return list.filter((item) => item.isComplete);
          case 'Show Uncompleted':
            return list.filter((item) => !item.isComplete);
          default:
            return list;
        }
      },
    });
    

    filteredTodoListState会持续跟踪todoListFilterStatetodoListState 这两个依赖项的变化,当其中一个变化时,filteredTodoListState会被重新执行。

    然后我们来实现 TodoListFilters 组件。

    function TodoListFilters() {
      const [filter, setFilter] = useRecoilState(todoListFilterState);
    
      const updateFilter = ({target: {value}}) => {
        setFilter(value);
      };
    
      return (
        <>
          Filter:
          <select value={filter} onChange={updateFilter}>
            <option value="Show All">All</option>
            <option value="Show Completed">Completed</option>
            <option value="Show Uncompleted">Uncompleted</option>
          </select>
        </>
      );
    }
    
    1. TodoListStats
      展现todoList数量,completed数量, uncomplted数量, completed所占百分比。
      创建 todoListStatsState seletor。
    const todoListStatsState = selector({
      key: 'todoListStatsState',
      get: ({get}) => {
        const todoList = get(filteredTodoListState);
        const totalNum = todoList.length;
        const totalCompletedNum = todoList.filter((item) => item.isComplete).length;
        const totalUncompletedNum = totalNum - totalCompletedNum;
        const percentCompleted = totalNum === 0 ? 0 : totalCompletedNum / totalNum;
    
        return {
          totalNum,
          totalCompletedNum,
          totalUncompletedNum,
          percentCompleted,
        };
      },
    });
    

    读取 todoListStatsState

    function TodoListStats() {
      const {
        totalNum,
        totalCompletedNum,
        totalUncompletedNum,
        percentCompleted,
      } = useRecoilValue(todoListStatsState);
    
      const formattedPercentCompleted = Math.round(percentCompleted * 100);
    
      return (
        <ul>
          <li>Total items: {totalNum}</li>
          <li>Items completed: {totalCompletedNum}</li>
          <li>Items not completed: {totalUncompletedNum}</li>
          <li>Percent completed: {formattedPercentCompleted}</li>
        </ul>
      );
    }
    

    相关文章

      网友评论

          本文标题:Recoil学习(二)---实现TodoList

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