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

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

使用场景:获取Table数据等

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

  1. import React, { useState, useEffect } from 'react'
  2. export default () => {
  3. const [page, setPage] = useState(1)
  4. const [dataSource, setDataSource] = useState([])
  5. funtion loadData( ) {
  6. getdata({
  7. page,
  8. pageSize
  9. }).then(res => setDataSource(res.data))
  10. }
  11. // useEffect方法为函数组件渲染的时候会默认触发一次,当page参数变化的时候,loadData方法也会触发一次
  12. // useEffect的第二个参数为一个数组,可以添加多个数组对象,如[page, search]
  13. useEffect(loadData, [page])
  14. }

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

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

  1. import React, { useState, useEffect } from 'react'
  2. export default () => {
  3. const [count, setCount] = useState(0)
  4. const timer = setInterval(() => {
  5. setCount(count + 1)
  6. }, 1000)
  7. // useEffect方法的第一个参数是一个函数,函数可以return一个方法,这个方法就是在组件销毁的时候会被调用
  8. useEffect(() => {
  9. return () => {
  10. clearInterval(timer)
  11. }
  12. }, [])
  13. }

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

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

  1. import React, { useState, useEffect } from 'react'
  2. import { Input } from 'antd'
  3. export const Child = React.forwardRef((props, ref) => {
  4. // 当外部传入ref时,可以通过forwardRef的第二个参数获取到ref属性的值
  5. // ref如果有值,就赋值把控制权给父组件;若为空,则可以在子组件内部控制Input
  6. const inputRef = ref || React.createRef()
  7. return <>
  8. <Input ref={inputRef} />
  9. </>
  10. })
  11. export default class Father extends React.Component {
  12. constuctor (props) {
  13. super(props)
  14. this.inputRef = React.createRef()
  15. }
  16. componentDidMount () {
  17. // 1妙后让Child组件的Input标签聚焦
  18. setTimeout(() => {
  19. this.textRef.current.focus()
  20. }, 1000)
  21. }
  22. render () {
  23. // 通过ref传递inputRef参数,从而获取到Input的控制权
  24. return <>
  25. <Child ref={this.inputRef} />
  26. </>
  27. }
  28. }

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

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

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

  1. // utils.js
  2. import { useState } from 'react'
  3. export default (initial, setPage) => {
  4. const [state, setState] = useState(initial)
  5. return [state, function (newState) {
  6. // 每次筛选条件变化的时候,就重新设置到第一页,
  7. setPage && setPage(1)
  8. // 新的覆盖参数覆盖掉老的参数
  9. setState({ ...state, ...newState })
  10. }]
  11. }
  12. // index.js
  13. import React, { useState, useEffect } from 'react'
  14. import { Table } from 'antd'
  15. import useMergeFilter from './utils'
  16. export default () => {
  17. const [dataSource, setDataSource] = useState([])
  18. const [page, setPage] = useState(1)
  19. const [total, setTotal] = useState(0)
  20. const [filter, setFilter] = useMergeFilter({ keyword: undefined, status: '' }, setPage)
  21. function loadData () {
  22. // 将参数展开传入
  23. getdata({ page, pageSize, ...filter }).then(res => setDataSource(res.data))
  24. }
  25. // 每次filter和page变化都会触发loadDate函数运行
  26. useEffect(loadData, [filter, page])
  27. return <>
  28. <div className='filter'>
  29. // 只需在回调函数里执行setFilter并传入需要的参数,就能触发列表更新
  30. <Input.Search placeholder='搜索' onSearch={value => setFilter({ keyword: value })} />
  31. <Select defaultValue='' onChange={value => setFilter({ status: value })}>
  32. <Select.Option value='A'>A</Select.Option>
  33. <Select.Option value='B'>B</Select.Option>
  34. </Select>
  35. </div>
  36. <Table
  37. columns={columns()}
  38. dataSource={dataSource}
  39. />
  40. </>
  41. }

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

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

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

  1. import React, { useState, useEffect } from 'react'
  2. import { Form, Button } from 'antd'
  3. // 抛出函数组件的时候,通过Form.create()方法生成的新的组件,可以通过({ form })的形式拿到整个表单的form对象
  4. // 下面就可以随心所欲的操作form内的表单数据了
  5. const Demo = ({ form }) => {
  6. const handleSubmit = (e) => {
  7. e.preventDefault()
  8. form.validateFields((err, values) => {
  9. console.log('err', err)
  10. console.log('values', values)
  11. })
  12. }
  13. <Form onSubmit={handleSubmit}>
  14. <div>
  15. <FormItem label='用户ID'>
  16. {getFieldDecorator('id', {
  17. initialValue: '',
  18. })(
  19. <Input placeholder='输入用户名id' />
  20. )}
  21. </FormItem>
  22. <Form.Item>
  23. <Button type='primary' htmlType='submit'>提交</Button>
  24. </Form.Item>
  25. </div>
  26. </Form>
  27. }
  28. const WrappedRegistrationForm = Form.create()(Demo)
  29. export default WrappedRegistrationForm