如何使用React Hooks建立一个待办事项列表

栏目: IOS · Android · 发布时间: 5年前

内容简介:原文地址:React v16.7.0-alpha 引入了

原文地址: How to Build a Todo List with React Hooks

如何使用React Hooks建立一个待办事项列表

React v16.7.0-alpha 引入了 钩子(Hooks) 。开心!

什么是钩子(Hooks)?

钩子是能让你在没有用es6类的情况下使用React的状态, 生命周期钩子这些特性的功能。

优势:

  • 隔离状态相关逻辑,使测试更加容易
  • 不需要使用渲染属性或者高阶组件就可以共享状态相关逻辑
  • 根据逻辑而不是生命周期钩子来分离应用程序的关注点
  • 避免ES6类,因为它们很奇怪,不是真正的类,甚至会误导有经验的JavaScript开发人员

查看更多: React’s official Hooks intro

不要在生产环境使用

写这篇文章时,钩子还处于内部测试(alpha)阶段。它们的API随时都可能改变。

我建议你在你的业余项目中体验钩子,在它们成为稳定版本之前,不要在线上代码中使用。

构建事项列表

如何使用React Hooks建立一个待办事项列表

待办事项清单是使用广泛的例子,理由很充分——它们是很棒的练习工具。无论你想尝试任何语言或库我都推荐使用它。

在这个例子中,我们只实现其中的一小部分功能:

  • 使用Material Design展示事项列表
  • 通过input添加事项
  • 删除事项

配置

这是 githubCodeSandbox 的地址

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:

如何使用React Hooks建立一个待办事项列表

我们已经设置了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的更新方法。

所以我们把它们叫做 valuesetValue , 并使用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哦)

如何使用React Hooks建立一个待办事项列表

对事项列表(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 中。

我们现在可以添加事项了!

如何使用React Hooks建立一个待办事项列表

清除input框

现在添加新的事项后,我们没有把input清空,这是不好的用户体验!

我们只需要在 TodoForm.js 中做一点小改动,就可以修复它。

<form
  onSubmit={event => {
    event.preventDefault();
    saveTodo(value);
    setValue('');
  }}
>

当事项被保存后,我们就把form的state变成空字符串。

现在看起来很好了!

如何使用React Hooks建立一个待办事项列表

删除事项

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 的事项保存下来。

删除功能完成!

如何使用React Hooks建立一个待办事项列表

抽取事项列表(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);

现在一切工作正常!

如何使用React Hooks建立一个待办事项列表

抽取表单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


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

CSS实战精粹

CSS实战精粹

(美)克拉夫特 / 李方进 / 电子工业 / 2008-1 / 59.80元

《CSS实战精粹》囊括了CSS工作原理的所有细节,主要介绍了能够在项目中使用的具体CSS设计技巧,包括CSS布局、创建一般页面元素以及如何排版从而使内容兼具可读性和艺术性。另外,《CSS实战精粹》还讨论了CSS中一些常见的问题,给出了一些解决办法。一起来看看 《CSS实战精粹》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

在线进制转换器
在线进制转换器

各进制数互转换器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具