跳至主要內容

原子

原子包含應用程式狀態的真實來源。在我們的待辦事項清單中,真實來源會是一個物件陣列,每個物件都代表一個待辦事項項目。

我們將把我們的清單原子稱為 todoListState,並使用 atom() 函式建立它

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

我們賦予原子一個獨特的 key,並將 default 值設定為一個空陣列。若要讀取此原子的內容,我們可以在 TodoList 元件中使用 useRecoilValue() 掛勾

function TodoList() {
const todoList = useRecoilValue(todoListState);

return (
<>
{/* <TodoListStats /> */}
{/* <TodoListFilters /> */}
<TodoItemCreator />

{todoList.map((todoItem) => (
<TodoItem key={todoItem.id} item={todoItem} />
))}
</>
);
}

將中止註解的元件實作在以下各節中。

若要建立新的待辦事項項目,我們需要存取設定函式,這個函式將更新 todoListState 的內容。我們可以在 TodoItemCreator 元件中使用 useSetRecoilState() 掛勾取得設定函式

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++;
}

請注意我們使用設定函式的更新器表單,這樣我們才能根據舊的待辦事項清單建立一個新的待辦事項清單。

TodoItem 元件將顯示待辦事項項目的值,同時允許您變更其文字並刪除項目。我們使用 useRecoilState() 讀取 todoListState,並取得我們用來更新項目文字、標示為已完成以及刪除項目的設定函式

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)];
}

這樣我們就有了功能完整的待辦事項清單!在下一節中,我們將了解如何使用選擇器提升我們的清單至新的境界。