内容简介:原文地址:React v16.7.0-alpha 引入了
原文地址: How to Build a Todo List with React Hooks
React v16.7.0-alpha 引入了 钩子(Hooks) 。开心!
什么是钩子(Hooks)?
钩子是能让你在没有用es6类的情况下使用React的状态, 生命周期钩子这些特性的功能。
优势:
- 隔离状态相关逻辑,使测试更加容易
- 不需要使用渲染属性或者高阶组件就可以共享状态相关逻辑
- 根据逻辑而不是生命周期钩子来分离应用程序的关注点
- 避免ES6类,因为它们很奇怪,不是真正的类,甚至会误导有经验的JavaScript开发人员
查看更多: React’s official Hooks intro
不要在生产环境使用
写这篇文章时,钩子还处于内部测试(alpha)阶段。它们的API随时都可能改变。
我建议你在你的业余项目中体验钩子,在它们成为稳定版本之前,不要在线上代码中使用。
构建事项列表
待办事项清单是使用广泛的例子,理由很充分——它们是很棒的练习工具。无论你想尝试任何语言或库我都推荐使用它。
在这个例子中,我们只实现其中的一小部分功能:
- 使用Material Design展示事项列表
- 通过input添加事项
- 删除事项
配置
这是 github 和 CodeSandbox 的地址
git clone https://github.com/yazeedb/react-hooks-todo cd react-hooks-todo npm install
master分支已经实现了这些功能,如果你想自己跟着实现,请切到start分支。
git checkout start
启动工程
npm start
这个应用应该跑在 localhost:3000 上,这是初始UI:
我们已经设置了material-ui来给页面一个专业的外观,现在我们加入更多功能!
ToDoForm 组件
添加一个新文件, src/TodoForm.js 。这是初始代码:
import React from 'react';
import TextField from '@material-ui/core/TextField';
const TodoForm = ({ saveTodo }) => {
return (
<form>
<TextField
variant="outlined"
placeholder="Add todo"
margin="normal"
/>
</form>
);
};
export default TodoForm;
通过组件名字,我们就知道它是用来添加事项的,它也就是我们的第一个钩子。
useState
看这段代码:
import { useState } from 'react';
const [value, setValue] = useState('');
useState 是一个接收初始状态(state)返回一个数组的函数。 console.log 它吧。
数组的第一个值是你的state现在的值,第二个值是state的更新方法。
所以我们把它们叫做 value 和 setValue , 并使用es6解构赋值对它们进行赋值。
对表单(Form)使用useState
我们的表单应该跟踪input的值并在保存提交时执行 saveTodo 方法。 useState 能帮我们实现它。
更新 updateForm.js , 这是更新之后的代码:
import React, { useState } from 'react';
import TextField from '@material-ui/core/TextField';
const TodoForm = ({ saveTodo }) => {
<b>const [value, setValue] = useState('');</b>
return (
<form
<strong>onSubmit={event => {</strong>
event.preventDefault();
saveTodo(value);
}}
>
<TextField
variant="outlined"
placeholder="Add todo"
margin="normal"
onChange={event => {
setValue(event.target.value);
}}
value={value}
/>
</form>
);
};
export default TodoForm;
回到 index.js ,引入并且使用这个组件。
...
import TodoForm from './TodoForm';
...
const App = () => {
return (
<div className="App">
<Typography component="h1" variant="h2">
Todos
</Typography>
<TodoForm saveTodo={console.warn} />
</div>
);
};
现在你在input输入的值已经可以被打印出来了。(记得敲enter哦)
对事项列表(todos)使用useState
我们的事项列表todos也需要state。在 index.js 中引入 useState 。初始state应该是空数组。
import React, { useState } from 'react';
...
const App = () => {
const [todos, setTodos] = useState([]);
return ...
TodoList组件
建立一个新文件: src/TodoList.js
大部分代码是来自Material-UI库的高级组件, 这是更新之后的代码:
import React from 'react';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
import ListItemText from '@material-ui/core/ListItemText';
import Checkbox from '@material-ui/core/Checkbox';
import IconButton from '@material-ui/core/IconButton';
import DeleteIcon from '@material-ui/icons/Delete';
const TodoList = ({ todos, deleteTodo }) => (
<List>
{todos.map((todo, index) => (
<ListItem key={index.toString()} dense button>
<Checkbox tabIndex={-1} disableRipple />
<ListItemText primary={todo} />
<ListItemSecondaryAction>
<IconButton
aria-label="Delete"
onClick={() => {
deleteTodo(index);
}}
>
<DeleteIcon />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
))}
</List>
);
export default TodoList;
它接收两个属性:
- todos: 事项数组,我们遍历数组,建立每一个事项
- deleteTodo: 点击一个事项的删除按钮触发这个方法,它接收一个参数: 索引,这个索引唯一标识每一个事项。
在 index.js 中引入这个组件。
...
import TodoList from './TodoList';
import './styles.css';
const App = () => { ...
并在 App 方法中使用它:
...
<TodoForm saveTodo={console.warn} />
<TodoList todos={todos} />
添加事项
还是在 index.js 中,编辑 TodoForm 的属性, saveTodo :
<TodoForm
saveTodo={todoText => {
const trimmedText = todoText.trim();
if (trimmedText.length > 0) {
setTodos([...todos, trimmedText]);
}
}}
/>
这里我们只是把空格去掉,把新的值添加到 todos 中。
我们现在可以添加事项了!
清除input框
现在添加新的事项后,我们没有把input清空,这是不好的用户体验!
我们只需要在 TodoForm.js 中做一点小改动,就可以修复它。
<form
onSubmit={event => {
event.preventDefault();
saveTodo(value);
setValue('');
}}
>
当事项被保存后,我们就把form的state变成空字符串。
现在看起来很好了!
删除事项
TodoList 为每一条事项都提供了索引,根据索引我们能找到我们想删除的事项。
// TodoList.js
<IconButton
aria-label="Delete"
onClick={() => {
deleteTodo(index);
}}
>
<DeleteIcon />
</IconButton>
在 index.js 中传递这个函数
<TodoList
todos={todos}
deleteTodo={todoIndex => {
const newTodos = todos
.filter((_, index) => index !== todoIndex);
setTodos(newTodos);
}}
/>
我们使用 setTodos 方法把所有不符合 index 的事项保存下来。
删除功能完成!
抽取事项列表(todos)的useState
文章开头我提到 钩子便于分离状态和组件的逻辑。所以我们在这个应用中可以这样做。
新建一个文件叫 src/useTodoState.js
import { useState } from 'react';
export default initialValue => {
const [todos, setTodos] = useState(initialValue);
return {
todos,
addTodo: todoText => {
setTodos([...todos, todoText]);
},
deleteTodo: todoIndex => {
const newTodos = todos
.filter((_, index) => index !== todoIndex);
setTodos(newTodos);
}
};
};
这就是 index.js 中原来的代码,我们只是把它分离出来了!我们的状态处理逻辑不再和组件混在一起了!
现在我们只需要引入它,这是更新之后的代码:
import React from 'react';
import ReactDOM from 'react-dom';
import Typography from '@material-ui/core/Typography';
import TodoForm from './TodoForm';
import TodoList from './TodoList';
import useTodoState from './useTodoState';
import './styles.css';
const App = () => {
const { todos, addTodo, deleteTodo } = useTodoState([]);
return (
<div className="App">
<Typography component="h1" variant="h2">
Todos
</Typography>
<TodoForm
saveTodo={todoText => {
const trimmedText = todoText.trim();
if (trimmedText.length > 0) {
addTodo(trimmedText);
}
}}
/>
<TodoList todos={todos} deleteTodo={deleteTodo} />
</div>
);
};
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
现在一切工作正常!
抽取表单input中的useState
我们可以对表单做同样的处理!
新建一个文件: src/useInputState.js
import { useState } from 'react';
export default initialValue => {
const [value, setValue] = useState(initialValue);
return {
value,
onChange: event => {
setValue(event.target.value);
},
reset: () => setValue('')
};
};
现在 todoForm.js 应该变成这样:
import React from 'react';
import TextField from '@material-ui/core/TextField';
import useInputState from './useInputState';
const TodoForm = ({ saveTodo }) => {
const { value, reset, onChange } = useInputState('');
return (
<form
onSubmit={event => {
event.preventDefault();
saveTodo(value);
reset();
}}
>
<TextField
variant="outlined"
placeholder="Add todo"
margin="normal"
onChange={onChange}
value={value}
/>
</form>
);
};
export default TodoForm;
现在我们全部完成了!
希望你喜欢!!
谢谢!
作者: Yazeed Bzadough
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 产品待办事项列表梳理 Product Backlog Grooming
- 微软待办事项To-Do Windows 10 UWP版更新:支持多账户切换
- 禅道 9.8.stable 发布,增强待办功能和消息通知功能
- 喧喧 1.5.0 优化服务器性能,支持将消息创建为然之待办
- [ Laravel从入门到精通 ] 测试系列 —— 通过测试驱动开发构建待办任务项目(一):后端 API 接口篇
- [ Laravel从入门到精通 ] 测试系列 —— 通过测试驱动开发构建待办任务项目(二):前端功能和浏览器...
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web Security Testing Cookbook
Paco Hope、Ben Walther / O'Reilly Media / 2008-10-24 / USD 39.99
Among the tests you perform on web applications, security testing is perhaps the most important, yet it's often the most neglected. The recipes in the Web Security Testing Cookbook demonstrate how dev......一起来看看 《Web Security Testing Cookbook》 这本书的介绍吧!