创建项目
- 首先通过vite脚手架启动一个react项目
pnpm create vite
- 安装
tailwindcss和daisyui
npm install -D tailwindcss
npx tailwindcss init
npm i -D daisyui@latest
编写代码
- 编写基本结构样式
这里用到了语义化标签 :)
<div className="p-4 w-96 h-96 bg-slate-300 mx-auto mt-32 rounded-lg font-bold">
<h1 className="text-2xl text-center mb-2">待办事项</h1>
<header className="flex">
<input value={inputValue} onKeyDown={useKeydownHook(add, 'Enter')} onChange={(e) => setInputValue(e.target.value)} type="text" placeholder="Type here" className="input input-bordered w-full max-w-xs" />
<button onClick={add} className="btn ml-2">添加</button>
</header>
<main>
{
todoList.map( (val, idx) => <Item key={val.id} value={val} index={idx} onCheck={onCheck} onDelete={onDelete} /> )
}
</main>
</div>
- 封装待办事项子组件
这里其实不用单独封装,统一写成一整个待办事项列表更加方便,将列表拆开成单个反而需要额外的通信开销。不过笔者为了熟悉react,多做了一步
<div className="p-4 rounded-xl flex justify-between items-center mt-4 bg-white">
<div className="flex">
<input onChange={onCheckChange} checked={value.isDone} type="checkbox" className="checkbox checkbox-primary" />
<label className="ml-2">{ value.title }</label>
</div>
<button onClick={onDelete} className="btn btn-sm btn-error">删除</button>
</div>
- 编写业务逻辑
通过数组下标来实现父子通信,其实原理和封装成整个列表一样,只不过这里需要单独将待办项的index传递过去
const add = () => {
if(!inputValue) return
setTodoList([...todoList, {
id: new Date().getTime(),
title: inputValue,
isDone: false
}])
setInputValue("")
}
const onCheck = (id: number) => {
const newTodoList = [...todoList]
newTodoList[id].isDone =!newTodoList[id].isDone
setTodoList(newTodoList)
}
const onDelete = (id: number) => {
const newTodoList = [...todoList]
newTodoList.splice(id, 1)
setTodoList(newTodoList)
}
- 本地持久化
const [inputValue, setInputValue] = useState("")
const [todoList, setTodoList] = useState<TodoItem[]>([])
useEffect(() => {
const localTodoList = localStorage.getItem("todoList")
if(localTodoList) {
setTodoList(JSON.parse(localTodoList))
}
}, [])
useEffect(() => {
localStorage.setItem("todoList", JSON.stringify(todoList))
}, [todoList])
- 封装hook
每次键盘打完字都需要操作鼠标去添加不太方便,于是想到了监听键盘的回车事件。搜了一下发现react并没有vue的@click.enter的语法糖。需要在keydown事件处理函数里面单独去判断key的值,有些麻烦。为了练手,这里决定多此一举封装一个keydown Hook。
function useKeydownHook(callback: () => void, type: string) {
return (e: React.KeyboardEvent) => {
if(e.key === type) {
callback()
}
}
}
这样就可以灰常方便的绑定特定的键盘值了
<input onKeyDown={useKeydownHook(add, 'Enter')} />
总结
在该demo中用到了以下知识点:
- tsx
- useState
- useEffect
- react的class、事件监听
- 父子组件通信,函数式组件
- 自定义Hook