TS中使用hooks绑定antd组件(例:checkbox与checkboxgroup实现全选关联)
这篇文章是综合了ts+react16+hooks+antd的搬砖技术提升篇,对提升原理剖析能力及技术覆盖面的扩充非常有益。
扫码加微信前端二、三群(一群已满) :BAT大厂资深大牛定期推送面经与源码分析,各平台大牛优秀文章推荐,更有内推跳槽咨询、视频资源共享、学习资料文章pdf面经网盘资源等等福利。加入我们一起进步。
群内分享每日一题: 题目传送门
前端电子书大全: 电子书
Hooks为何要出现
生命周期钩子函数里的逻辑混乱
我们通常希望一个函数只做一件事情,但我们的生命周期钩子函数里通常同时做了很多事情。比如我们需要在
componentDidMount
中发起ajax请求获取数据,绑定一些事件监听等等。同时,有时候我们还需要在
componentDidUpdate
做一遍同样的事情。当项目变复杂后,这一块的代码也变得不那么直观。
classes使人困惑
我们用class来创建react组件时,还有一件很麻烦的事情,就是this的指向问题。为了保证this的指向正确,我们要经常写这样的代码:
this.handleClick = this.handleClick.bind(this)
,或者是这样的代码:
<button onClick={() => this.handleClick(e)}>
。一旦我们不小心忘了绑定this,各种bug就随之而来,很麻烦。
在ES的语言特性里,你在开发时不适应、甚觉繁琐的,hooks可以帮你 解决以下问题(优势)
1、无需继续考虑是写一个无状态组件(Function)还是有状态组件(Class) ---- 使用hooks,再也不需要写Class,所有组件都将是Function(形式为React.FC)
2、你还在为搞不清使用哪个生命周期钩子函数而日夜难眠吗? —— 使用Hooks,生命周期钩子函数可以先丢一边了
3、你还在为组件中的this指向而晕头转向吗? —— Class都不再使用了,哪里还有this?你的人生第一次不再需要面对this。
hooks中最为重要的几个钩子函数useState,useEffect,useRefs,useContent等,参考简单例子:
import { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
Example
作为一个函数,但这个函数却有自己的状态(count),同时它还可以更新自己的状态(setCount)。除了
useState
这个hook外,还有很多别的hook,比如
useEffect
提供了类似于
componentDidMount
等生命周期钩子的功能,
useContext
提供了上下文(context)的功能等等,全部都封装好了供你使用。
useState
useState是用来声明状态变量的方法函数,其中const[count, setCount]声明了一个状态变量count,把它的初始值设为0,同时提供了一个可以更改count的函数setCount(语法:es6解构赋值),读取状态再也不需要使用this.state.count这种形式了。
神奇的是setCount可以记录count之前的状态,参考:
同时react根据useState的出现顺序保证多个state之间保持独立状态(不会互相影响)
let showFruit = true;
function ExampleWithManyStates() {
const [age, setAge] = useState(42);
if(showFruit) {
const [fruit, setFruit] = useState('banana');
showFruit = false;
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
//第一次渲染
useState(42); //将age初始化为42
useState('banana'); //将fruit初始化为banana
useState([{ text: 'Learn Hooks' }]); //...
//第二次渲染
useState(42); //读取状态变量age的值(这时候传的参数42直接被忽略)
// useState('banana');
useState([{ text: 'Learn Hooks' }]); //读取到的却是状态变量fruit的值,导致报错
由此可见,react规定我们必须把hooks写在函数的最外层,不能写在if...else等条件语句当中,来确保hooks的执行顺序一致。
useEffect(异步执行)
Effect hooks的功能例子:
import { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// 类似于componentDidMount 和 componentDidUpdate:
useEffect(() => {
// 更新文档的标题
document.title = `You clicked ${count} times`;
return (
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
react16不使用hooks,使用class实现一个有状态组件(与上方的进行比较较为复杂)
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
componentDidMount() {
document.title = `You clicked ${this.state.count} times`;
componentDidUpdate() {
document.title = `You clicked ${this.state.count} times`;
render() {
return (
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
有状态组件通常会产生很多的 副作用(side effect) ,比如发起ajax请求获取数据,添加一些监听的注册和取消注册,手动修改dom等等。我们之前都把这些副作用的函数写在生命周期函数钩子里,比如componentDidMount,componentDidUpdate和componentWillUnmount。而现在的 useEffect 就相当与这些声明周期函数钩子的 集合体, 以一抵三。
每个side effect都给一个effect hooks就不会像之前一样将状态都保存至didmount中了,同时还不用考虑在哪个周期中可以使用setState。
TS绑定hooks
我们所有的组件都可以使用以下形式
const JobModalForm: React.FC<FormComponentProps & JobModalFormPropsType> = props => {
......//各种方法
return(
......
export default Form.create()(JobModalForm)
//暴露出来供其他组件调用
我们按照上述模板写出一个可复用的自定义hook,当你的组件想用什么功能时,直接在组件里调用这个hook即可。形式与 高阶组件 的形式类似,数据传输结果又与 render props (渲染属性)类似。
其中 React.FC 为 React TypeScript 的一个函数组件类型。这部分内容和原书内容不一致,原书内容为 React.SFC ,函数组件SFC英文全称为“Stateless Function Components”,由于作者编写本书时hook还没成为正式标准,hooks的出现允许包含 state 和 React lifecycle。原来的英文缩写释义不能准确表达此意,所以使用 React.FC 来替换 React.SFC ,结合hooks后SFC存在即无意义。
使用 泛型 框定出函数组件的类型,更加严谨规范。
结合antd中我们可以使用
const { getFieldDecorator, setFieldsValue, getFieldValue, validateFields, resetFields } = props.form
中的props.form中的特定方法获取想要的内容。
使用useState将checkbox与checkboxgroup绑定
官方文档中使用React16针对多state关联checkbox与checkboxgroup,其中关注点为checkbox中的value,checkboxgroup中的checkedList,indeterminate为控制checkbox中全选状态的样式, 加入indeterminate后会出现三种样式,如何通过boolen控制三种样式的展示 ?借助checked的状态控制不同样式的内容
state = {
checkedList: defaultCheckedList,
indeterminate: true,
checkAll: false
onChange = checkedList => {
this.setState({
checkedList,
indeterminate:
!!checkedList.length && checkedList.length < plainOptions.length,
checkAll: checkedList.length === plainOptions.length
onCheckAllChange = e => {
this.setState({
checkedList: e.target.checked ? plainOptions : [],
indeterminate: false,
checkAll: e.target.checked
render() {
console.log(this.state.checkedList)
return (
<div style={{ borderBottom: "1px solid #E9E9E9" }}>
<Checkbox
indeterminate={this.state.indeterminate}
onChange={this.onCheckAllChange}
checked={this.state.checkAll}
Check all
</Checkbox>
<br />
<CheckboxGroup
options={plainOptions}
value={this.state.checkedList}
onChange={this.onChange}
使用hooks绑定多关联组件
// 选择数据批次 ALL勾选change
const onDcCheckboxChange = (e: CheckboxChangeEvent) => {
setIndeterminate(false)//空或者全选
setBoxChecked(e.target.checked)
let finResult = boxChecked ? [] : newarray
setNameArray(finResult)
// 单独选择后的勾选
const inDcCheckboxChange = e => {
//当前的e为复选框后面的值为checkedvalue
//通过this.state.nameArray保存当前选项的选中状态,并将inDccheckboxchange与onDcCheckboxChange关联了起来
setNameArray(e)
setIndeterminate(!!e.length&&e.length<=newarray.length)//true输出&&后面的,false直接输出false
setBoxChecked(e.length==newarray.length)
使用onDcCheckboxChange控制全选按钮,checkbox的onchange方法中传递为Function(e:Event),checkboxgroup的onchange方法中传递的为checkedValue(选中的值,格式为Array)
// 使用checked与indeterminate协同控制checkbox的显示,checkbox在绑定了全选的情况下有三种展示形态,是难点请记住