介绍
React Hooks 正在改变我们在 React 中开发的方式,解决一些我们最大的问题,useEffect
Hook 使我们能够替代重复的组件生命周期代码。
基本上,胡克是一个特殊的功能,允许您插入
反应功能。胡克是一个很好的解决方案,如果您之前已经编写了一个功能组件,并意识到您需要添加状态。
如果你对Hooks是新手,并且想要一个概述,请查看React Hooks的介绍(https://andsky.com/tech/tutorials/react-hooks)。
这篇文章假定你熟悉useState
链接。如果你没有,不要害怕! 如果你花了一点时间使用 使用状态链接将基于类的反应组件转换为功能组件,你将走在正确的道路上!
关于使用效果
useEffect
是使用副作用
的缩写。 效果是当我们的应用程序与外部世界进行反应时,例如使用API。 它允许我们根据某些变化运行函数。
关于我们的APP
我们将使用 reactstrap来简化我们的格式化和 axios来调用一个外部愚蠢的API。
具体来说,我们正在使用 jsonplaceholder 来在我们的初始组件安装上提取虚假用户数据。
然后,我们正在触发该组件基于用户点击重新渲染并引入有关用户的额外数据。
开始的
只需用起始代码克隆重复:
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
。
<$>[注意]您的应用现在应该看起来像下面的屏幕截图。
让我们开始用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};
我们基本上正在从以前的componentDidMount
和componentDidUpdate
函数中提取这种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 ] );