从 React 组件分钟分析 React.API 的使用场景

247 阅读3分钟

api 基础与实践分析

值得 await 的 React.useState

useState 使用很简单,但是为了避免过多的 re-render, 尽可能的少的定义 useState. 在开发的时候,能使用 useRef 代替的尽量使用 useRef 代替。所以规则是:

  • 最少的 useState 定义(在 react 中可能要更新批量更新 useState 的 setState)
const page = () => {
    // 假如我们的页面里面有很多的 select
    const [selectList1, setSelectList1] = useState([])
    const [selectList2, setSelectList2] = useState([])
    const [selectList3, setSelectList3] = useState([])
    
    const getSelectData = async () => {
    const res = awiat request({
           url: 'your_path',
           options: {
               methods: 'get',
               params: {count, pageSize: count}
           }
       })
       
       setSelectList1(res.result.data1) // re-render 1
       setSelectList2(res.result.data2) // re-render 2 
       setSelectList3(res.result.data3) // re-render 3
    }
    
    useEffect(() => {
           getSelectData()
    }. [])
    
    return (
        <div>
            {selectList1.map((item) => { return item.name})}
            {selectList2.map((item) => { return item.title})}
            {selectList3.map((item) => { return item.age})}
        </div>
    )
}
  • 不要定义过多的 state

  • state 是在试图展示的更新用的,有些不需要到试图的,放在内存里面就可以了,推荐使用 useRef 保存

  • 异步的 setState 的问题,使用异步函数来解决

const page = () => {
    const [count, setCount] = useState<number>(1)
    
    return (
        <div>
            <button onClick={async () => {
               await setCount(count + 1);
               
               const res = awiat request({
                   url: 'your_path',
                   options: {
                       methods: 'get',
                       params: {count, pageSize: count}
                   }
               })
               
              // other
            }}>+1</button>
        </div>
    ) 
}

所有说 async/await 可能更加般配欧

React.cloneElement

  1. React.clone API是单独的克隆一个 React 组件或者 DOM 节点。克隆之后我们就可以方便的在上面给 props。
import React from 'react'

const TestClone = (props) => {
    const [visiable, setVisiable] = react.useState<boolean>(false);
    const {trigger, children} = props;
    
    return (
        <div>
            {visiable ? <div>
                {children}
            </div> : null}
            {React.cloneElement(trigger, {trigger.props, onClick: () => {
                setVisiable(!visiable)
            })}
        </div>
    )
}

export default TestClone;

说明:

  • trigger 是一个React 节点,使用 React.cloneElement API 方便的克隆一个这个节点,然后在它基础上添加了新的点击事件。于是当我们点击 trigger 的时候,就会切换 children 节点的现实与隐藏。

这样做的好处,一个节点暴露给外部,状态在内部维护。

总结:cloneElement 是一个很灵活的 API, 得益于第二参数可以用来组合不同的 props。生成一个新的节点。如果你需要对当前的节点 props 进行增删改查操作。使用 cloneElement 是一个很不错的选择。

React 中如何获取子组件的中的数据

场景:我们以偶一个上传组件的封,在上传之前,需要获取 token,其实我们并不关心 token, 只是关心上传之后,服务器返回的数据,这些数据也不需要需要响应到页面。所以可能并不需要使用 useState 定义响应数据

  • API React.useImperativeHandle

useImperativeHandle 钩子函数,需要与 React.forward 来进行配合使用。useImperativeHandle 钩子函数接受两个参数,第一个就是传入子组件的 ref, 第二参数是 函数,此函数返回的是我们能在父组件中访问的数据。

使用:

  1. 父组件中定义 ref
  2. 在父组件中使用子组件,并绑定 ref 属性
  3. 子组件配合 forwardRef 使用,拿到 ref
  4. 绑定 useImperatoveHandle 绑定目标数据
  5. ref 指向 dom 或者其他子组件的值
import React, {useState, useImperativeHandle } from 'react';

const ChildComponent = React.forwardRef((props, ref) => {

    const [data1, setData1] = useState(1)
    
    const onClick = () => {
        // your code
    }
    useImperativeHandle(ref, () => ({
        data: data1,
        dom1: ref.current,
        event1: onClick
    })) 
    
    return (
        <div ref={ref} onClick={onClick}>
          react- component - children- data - get methods
        </div>
    )
})

方便的从组件中拿到,我们想要的数据,而不需要定于多余的 state, setState。

Reactc.Children

问题

  1. React 为什么要单独提提供操作 React.Children 的 API?
  2. React.Children 解决了什么问题?

useRef 中定义的数据,会 使得 useEffect 中的 effect 函数,被调用吗?

其实如果我们想让一个页面刷新,其实就是在 useEffect 中只执行一次的,要它强制更新一次。

  • statas 是会更新试图
  • ref 的变化,理论上也使得副作用重新执行