原子
原子包含我们应用程序状态的真实来源。在我们的待办事项列表中,真实来源将是一个对象数组,每个对象代表一个待办事项。
我们将我们的列表原子命名为 todoListState
,并使用 atom()
函数创建它
const todoListState = atom({
key: 'TodoList',
default: [],
});
我们为原子提供一个唯一的 key
并将 default
值设置为一个空数组。要读取该原子的内容,我们可以在 TodoList
组件中使用 useRecoilValue()
hook
function TodoList() {
const todoList = useRecoilValue(todoListState);
return (
<>
{/* <TodoListStats /> */}
{/* <TodoListFilters /> */}
<TodoItemCreator />
{todoList.map((todoItem) => (
<TodoItem key={todoItem.id} item={todoItem} />
))}
</>
);
}
注释掉的组件将在接下来的部分中实现。
要创建新的待办事项,我们需要访问一个将更新 todoListState
内容的 setter 函数。我们可以在 TodoItemCreator
组件中使用 useSetRecoilState()
hook 获取 setter 函数
function TodoItemCreator() {
const [inputValue, setInputValue] = useState('');
const setTodoList = useSetRecoilState(todoListState);
const addItem = () => {
setTodoList((oldTodoList) => [
...oldTodoList,
{
id: getId(),
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>
);
}
// utility for creating unique Id
let id = 0;
function getId() {
return id++;
}
注意我们使用 setter 函数的更新程序形式,以便我们可以基于旧的待办事项列表创建一个新的待办事项列表。
TodoItem
组件将显示待办事项的值,同时允许你更改其文本并删除该项目。我们使用 useRecoilState()
来读取 todoListState
并获取一个 setter 函数,我们使用它来更新项目文本,将其标记为已完成并删除它
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)];
}
就这样,我们得到了一个功能完备的待办事项列表!在下一节中,我们将了解如何使用选择器将我们的列表提升到一个新的水平。