使用React Hook

做毕设学了点东西系列

好久没写React了,上次写React还在坚持类组件的写法,有点既然还能用就安于现状的感觉。今天本来只是想把之前一周速成的前端代码和后端联调通,但是发现类组件果然还是有缺点,生命周期和state改来改去的,想想还是埋头重读React的文档改成函数式组件吧。记录了一下最基本的操作。

函数式组件和Hook

一个函数就是一个组件,这个函数组件没有生命周期函数,没有this和内部状态(state)。而Hook就是为了我们在使用函数式组件的时候,仍然可以使用类组件中的state或者其他的特性。

写一个函数式组件

1
2
3
4
5
6
const TaskDetail = () => {
return (
<div>hello!</div>
); // return的就是在类组件中render的内容
}
export default TaskDetail;

使用state hook

1
2
3
import React, { useState } from 'react';
// 定义一个叫taskDetail的变量,初始值设置为空对象,在后面的代码中就可以使用setTaskDetail来更新这个state
const [taskDetail, setTaskDetail] = useState({});

使用effect hook获取api数据

在类组件中想要获取数据渲染的时候,一般会在生命周期中调用api,比如一个简单的例子

1
2
3
4
5
6
7
componentDidMount() {
const id = this.props.match.params.id;
const result = queryData(id);
this.setState({
taskDetail: result
})
}

这里就是使用了url中传过来的id,获取数据后设置state,关于setState的更新时机又有一些需要注意的点。effect hook做的事情很类似于componentDidMountcomponentDidUpdate可以完成的事情,实现各种不同的副作用(数据获取、设置订阅、手动更改DOM等)。在React文档里,详细讲述了无需清除和需要清除的的区别(返回函数与否)。下面举例的是一个无需清除的异步调用请求方法的effect。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const TaskDetail = (props) => {
const [taskDetail, setTaskDetail] = useState({});
useEffect(() => {
const id = props.match.params.id;
async function fetchData() {
const detail = await queryTaskDetail(id);
setTaskDetail(detail);
}
fetchData();
},[props.match.params.id]);
return (
// ...
);
}

这里使用effect的时候有几个注意的点:

  1. 如果使用async方法的话,不能直接加在useEffect(async () => {}这样,而是在内部写一个方法然后再调用
  2. useEffect的第二个可选参数定义了只有这个值发生变化的是才去调用这个effect,否则的话就跳过这个effect,实现了性能的优化

使用ref hook获取dom元素

React的Refs提供了一种方式让我们可以访问DOM节点,一般发生在强制修改组件的情况而不是正常的父子props数据流渲染的时候。
useRef返回一个可变的ref对象,它的current属性被初始化为传入的参数,返回的ref对象在组件的整个生命周期内保持不变。在每次渲染的时候返回的是同一个ref对象。当ref对象的内容发生变化的时候,不会引起组件的重新渲染。如果需要这么做的话(根据ref的变化运行一些代码),则需要使用回调ref(useCallback)来实现。
我的项目里用到的是实现局部table的刷新:

1
2
3
4
5
6
7
8
const actionRef = useRef(); // 初始化ref
<ProTable
actionRef={actionRef} // 挂载到这个table上
...
/>
actionRef.current.reload(); // 一些操作后进行更新

比如刷新的时候