美文网首页
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