在 React 中用 useEffect 挂钩取代组件生命周期

介绍

React Hooks 正在改变我们在 React 中开发的方式,解决一些我们最大的问题,useEffect Hook 使我们能够替代重复的组件生命周期代码。

基本上,胡克是一个特殊的功能,允许您插入反应功能。胡克是一个很好的解决方案,如果您之前已经编写了一个功能组件,并意识到您需要添加状态。

如果你对Hooks是新手,并且想要一个概述,请查看React Hooks的介绍(https://andsky.com/tech/tutorials/react-hooks)。

这篇文章假定你熟悉useState链接。如果你没有,不要害怕! 如果你花了一点时间使用 使用状态链接将基于类的反应组件转换为功能组件,你将走在正确的道路上!

关于使用效果

useEffect使用副作用的缩写。 效果是当我们的应用程序与外部世界进行反应时,例如使用API。 它允许我们根据某些变化运行函数。

关于我们的APP

我们将使用 reactstrap来简化我们的格式化和 axios来调用一个外部愚蠢的API。

具体来说,我们正在使用 jsonplaceholder 来在我们的初始组件安装上提取虚假用户数据。

Starter Code

然后,我们正在触发该组件基于用户点击重新渲染并引入有关用户的额外数据。

Starter Code, clicked

开始的

只需用起始代码克隆重复:

1$ git clone https://github.com/alligatorio/use-effect-hook
2$ npm i
3$ npm start

花一点时间来熟悉代码,特别是ClassBasedComponent.js文件。

你会注意到我们在这个文件中有两个生命周期方法,componentDidMount和componentDidUpdate。

 1async componentDidMount() {
 2  const response = await axios
 3    .get(`https://jsonplaceholder.typicode.com/users`);
 4
 5  this.setState({ users: response.data });
 6};
 7
 8async componentDidUpdate(prevProps) {
 9  if (prevProps.resource !== this.props.resource) {
10    const response = await axios
11      .get(`https://jsonplaceholder.typicode.com/users`);
12
13    this.setState({ users: response.data });
14  }
15};

这些都是async生命周期方法,呼吁 jsonplaceholder API 引入用户列表。

componentDidMount中,我们说在第一个渲染时,获取用户数据。接下来,在componentDidUpdate中,我们看看在props中是否有任何变化。

我们希望将生命周期方法凝聚到useEffect中,并创建一个基于函数的组件。

创建一个组件

而不是使用相同的 ClassBasedComponent.js 文件,创建一个名为 FunctionBasedComponent.js 的新文件,我们正在创建一个新的文件,以便我们可以对比和比较两者。

在您的终端中,您可以执行以下操作,从您的根目录创建新文件:

1$ touch FunctionBasedComponent.js

要帮助您开始,请将下面的代码复制并粘贴到新文件中:

 1import React, { useState, useEffect } from 'react';
 2import { Container, Button, Row } from 'reactstrap';
 3import axios from 'axios';
 4
 5const FunctionBasedComponent = () => {
 6  return (
 7    <Container className="user-list">
 8      <h1>My Contacts:</h1>
 9    </Container>
10  )
11};
12
13export default FunctionBasedComponent;

现在跳到你的App.js文件,导入你的FunctionBasedComponent.js文件,并用FunctionBasedComponent替换ClassBasedComponent

<$>[注意]您的应用现在应该看起来像下面的屏幕截图。

our starting useEffect app


让我们开始用useState初始化状态。

1const [ users, setUsers ] = useState([]);
2const [ showDetails, setShowDetails ] = useState(false);

要快速重复useState,以useState链接初始化state,我们声明我们的变量和与数组中的变量相符的函数,然后我们通过useState()我们希望初始化我们的变量参数。

*用户状态变量被初始化为一个空数组,并给出了设置用户的函数 *显示细节状态变量被初始化为的值,并分配给设置显示细节的函数

添加 API 呼叫

让我们继续,在我们的API调用中添加fetchUsers函数。

1const fetchUsers = async () => {
2  const response = await axios.get(`https://jsonplaceholder.typicode.com/users`);
3
4  setUsers(response.data);
5};

我们基本上正在从以前的componentDidMountcomponentDidUpdate函数中提取这种async呼叫。

请记住,我们不能直接在useEffect内使用一个async函数,如果我们想要调用一个async函数,我们需要在useEffect外界定义该函数,然后在useEffect内调用它。

使用效应论点

让我们谈谈一下useEffect链接一会儿,就像componentDidMount一样,useEffect会立即调用我们的函数。

1useEffect( () => {}, [ 'value' ]);

默认情况下,useEffect 会查看数组值是否不同,如果不同,则自动调用箭头函数。

1useEffect( () => {}, [ 'different value' ]);

让我们回到我们的代码编辑器,并在我们最新的功能下面添加useEffect链接,在那里我们将呼叫fetchUsers

在下面的代码中,我们正在查看用户对象,看看是否有任何变化。

1useEffect( () => { fetchUsers(users) }, [ users ] );

共同问题

  • 如果您不将数组传入使用效应夹,您的组件将连续重复加载
1useEffect( () => { fetchUsers(users) } );
  • 如果您通过一个空的数组,我们不会观察任何变量,因此它只会更新第一个渲染的状态,就像「componentDidMount」一样。
1useEffect( () => { fetchUsers(users) }, [] );
  • 每当我们在JavaScript中创建一个对象时,它在内存中是不同的对象. 虽然下面的代码看起来相同,但页面将重新渲染,因为每个对象都存储在不同的内存地址中。
1useEffect( () => { fetchUsers(users) }, [{ user: 'Alli Alligator' }] );

<$>[警告] 不等于! <$>

1useEffect( () => { fetchUsers(users) }, [{ user: 'Alli Alligator' }] );
  • useEffect 函数必须返回清理函数或无。

要演示触发另一个重新渲染,请将下面的代码复制并粘贴到您的FunctionBasedComponent.js文件中:

 1import React, { useState, useEffect } from 'react';
 2import { Container, Button, Row } from 'reactstrap';
 3import axios from 'axios';
 4
 5const FunctionBasedComponent = () => {
 6  const [ users, setUsers ] = useState([]);
 7  const [ showDetails, setShowDetails ] = useState(false);
 8
 9  const fetchUsers = async () => {
10    const response = await axios.get(`https://jsonplaceholder.typicode.com/users`);
11
12    setUsers(response.data);
13  };
14
15  useEffect( () => { fetchUsers(users) }, [ users ] );
16
17  const handleClick = event => { setShowDetails(!showDetails) };
18
19  return (
20    <Container>
21      {
22        users.map((user) => (
23          <ul key={ user.id }>
24            <li>
25              <strong>{ user.name }</strong>
26              <div>
27                <Button
28                  onClick={ handleClick }
29                >
30                  { showDetails ? "Close Additional Info" : "More Info"  }
31              </Button>
32               { showDetails &&
33                 <Container className="additional-info">
34                   <Row>
35                     { `Email: ${ user.email }` }
36                   </Row>
37                   <Row>
38                     { `Phone: ${ user.phone }` }
39                   </Row>
40                   <Row>
41                     { `Website: ${ user.website }` }
42                   </Row>
43                 </Container>
44               }
45              </div>
46            </li>
47          </ul>
48        ))
49      }
50    </Container>
51  )
52}
53
54export default FunctionBasedComponent;

现在我们有一个按钮中的onClick事件。在按钮上,改变了显示细节的状态,触发了重新渲染,将再次调用API,并带来我们需要的额外细节。

是啊!

 1async componentDidMount() {
 2    const response = await axios.get(`https://jsonplaceholder.typicode.com/users`)
 3    this.setState({ users: response.data })
 4};
 5
 6async componentDidUpdate(prevProps) {
 7  if (prevProps.resource !== this.props.resource) {
 8    const response = await axios.get(`https://jsonplaceholder.typicode.com/users`)
 9    this.setState({ users: response.data })
10  }
11};

变成:

1const fetchUsers = async () => {
2  const response = await axios.get(`https://jsonplaceholder.typicode.com/users`);
3
4  setUsers(response.data);
5};
6
7useEffect( () => { fetchUsers(users) }, [ users ] );
Published At
Categories with 技术
Tagged with
comments powered by Disqus