使用React Hook新特性遇到的一些问题

1,848 阅读4分钟

前言:

市面上对怎么使用React Hooks新特性的入门例子可以说是汗牛充栋,我都懒得写这些脱裤子放屁的文章,今天就把我自己开发遇到的一些痛点理一理写一哈,让自己以后也能有可以翻阅的资料,本文会持续更新个人遇到的和解决掉的关于Hooks方面的问题。

一、参数变化触发数据更新

使用场景:获取Table数据等

当Table数据的页码和筛选项变化的时候,想触发获取数据的方法运行

import React, { useState, useEffect } from 'react'

export default () => {
	const [page, setPage] = useState(1)
	const [dataSource, setDataSource] = useState([])
	
	funtion loadData( ) {
		getdata({
		    page,
		    pageSize
		}).then(res => setDataSource(res.data))
	}
	// useEffect方法为函数组件渲染的时候会默认触发一次,当page参数变化的时候,loadData方法也会触发一次
	// useEffect的第二个参数为一个数组,可以添加多个数组对象,如[page, search]
	useEffect(loadData, [page])
}

二、销毁函数组件的时候,怎么设置回调函数

使用场景:设置了定时器等方法的时候,组件销毁的时候清理定时器释放内存

import React, { useState, useEffect } from 'react'

export default () => {
	const [count, setCount] = useState(0)
	const timer = setInterval(() => {
		setCount(count + 1)
	}, 1000)
	// useEffect方法的第一个参数是一个函数,函数可以return一个方法,这个方法就是在组件销毁的时候会被调用
	useEffect(() => {
		return () => {
			clearInterval(timer)
		}
	}, [])
}

三、如何拿到函数组件内的ref三、如何拿到函数组件内的ref

使用场景:子组件内使用了一些输入框Input等组件的时候,想在父组件内获取子组件的Input的ref方法

import React, { useState, useEffect } from 'react'
import { Input } from 'antd'

export const Child = React.forwardRef((props, ref) => {
	// 当外部传入ref时,可以通过forwardRef的第二个参数获取到ref属性的值
	// ref如果有值,就赋值把控制权给父组件;若为空,则可以在子组件内部控制Input
	const inputRef = ref || React.createRef()
	return <>
		<Input ref={inputRef} />
	</>
})

export default class Father extends React.Component {
	constuctor (props) {
		super(props)
		this.inputRef = React.createRef()
	}
	
	componentDidMount () {
		// 1妙后让Child组件的Input标签聚焦
		setTimeout(() => {
		    this.textRef.current.focus()
		 }, 1000)
	}
	
	render () {
		// 通过ref传递inputRef参数,从而获取到Input的控制权
		return <>
			<Child ref={this.inputRef} />
		</>
	}
}

四、用函数组件制作Table列表,筛选条件让useState十分臃肿

使用场景:Table的筛选项有page、search、dateTime、order、type等等

如果给每个筛选项加一个useState来控制的话,不得不说代码会比较臃肿,难以维护且不优雅(装起来了就),下面就来解决一下这个痛点

// utils.js
import { useState } from 'react'
export default (initial, setPage) => {
  const [state, setState] = useState(initial)
  return [state, function (newState) {
  	// 每次筛选条件变化的时候,就重新设置到第一页,
    setPage && setPage(1)
	// 新的覆盖参数覆盖掉老的参数
    setState({ ...state, ...newState })
  }]
}

// index.js
import React, { useState, useEffect } from 'react'
import { Table } from 'antd'
import useMergeFilter from './utils'

export default () => {
	const [dataSource, setDataSource] = useState([])
	const [page, setPage] = useState(1)
    const [total, setTotal] = useState(0)
    const [filter, setFilter] = useMergeFilter({ keyword: undefined, status: '' }, setPage)
	
	function loadData () {
		// 将参数展开传入
		getdata({ page, pageSize, ...filter }).then(res => setDataSource(res.data))
	}
	// 每次filter和page变化都会触发loadDate函数运行
	useEffect(loadData, [filter, page])
	
	return <>
		<div className='filter'>
		  // 只需在回调函数里执行setFilter并传入需要的参数,就能触发列表更新
          <Input.Search placeholder='搜索' onSearch={value => setFilter({ keyword: value })} />
          <Select defaultValue='' onChange={value => setFilter({ status: value })}>
            <Select.Option value='A'>A</Select.Option>
            <Select.Option value='B'>B</Select.Option>
          </Select>
        </div>
		<Table
			columns={columns()}
            dataSource={dataSource}
		/>
	</>
}

五、新特性函数组件结合antd的表单form组件

使用场景:函数组件内使用表单,获取form属性

这个使用场景就比较多了,正常的类组件我们都会,antd的官方也有介绍;但用函数组件写有的同学就会有点懵,form去哪里取

import React, { useState, useEffect } from 'react'
import { Form, Button } from 'antd'

// 抛出函数组件的时候,通过Form.create()方法生成的新的组件,可以通过({ form })的形式拿到整个表单的form对象
// 下面就可以随心所欲的操作form内的表单数据了
const Demo  = ({ form }) => {
	const handleSubmit = (e) => {
		e.preventDefault()
		form.validateFields((err, values) => {
		  console.log('err', err)
		  console.log('values', values)
		})
	}
	<Form onSubmit={handleSubmit}>
		<div>
			<FormItem label='用户ID'>
				{getFieldDecorator('id', {
				initialValue: '',
				})(
				<Input placeholder='输入用户名id' />
				)}
			</FormItem>
			<Form.Item>
				<Button type='primary' htmlType='submit'>提交</Button>
			</Form.Item>
		</div>
	</Form>
}
const WrappedRegistrationForm = Form.create()(Demo)
export default WrappedRegistrationForm