React Hooks 教程之 useImperativeHandle

头部

终于到了这个系列最后一篇 hook 教程,其实还有几个 hook 没有介绍,有的是几乎用不到的,还有的是 React 18 版本新出的(不要再更新啦,老夫真的学不动啦)

说回正题,众所周知,React 是单向数据流,是由父组件传参给子组件,所以一般只能子组件调用父组件方法,但是实际业务复杂多变,有些场景就是需要父组件调用子组件,所以 React 也提供了这一方式,但是官方也说了,应当避免这种命令式的代码,破坏了 React 父不知子的原则

中部

useImperativeHandle 应当与 forwardRef 和 useRef 一起使用

  • useImperativeHandle 定义子组件暴露给父组件的属性或方法
  • forwardRef 暴露子组件的引用给父组件
  • useRef 父组件获取子组件的引用

正经

import React from "react";
import "./App.css";

type TChildRef = {
    data: number;
    getValue: (value: string) => string;
};

type TChildProps = {
    value: number;
};

const Child = React.forwardRef<TChildRef, TChildProps>((props, ref) => {
    const [state, setState] = React.useState(props.value);

    React.useImperativeHandle(ref, () => {
        return {
            data: state,
            getValue: (value) => {
                return value.repeat(5);
            },
        };
    });

    return <h1 onClick={() => setState((state) => state + 1)}>child state:{state}</h1>;
});

const App: React.FC = () => {
    const childRef = React.useRef<TChildRef>(null);

    return (
        <div>
            <Child ref={childRef} value={0} />
            <button
                onClick={() => {
                    console.log("data", childRef.current?.data);
                    console.log("getValue", childRef.current?.getValue("123"));
                }}
            >
                call child
            </button>
        </div>
    );
};

export default App;

运行效果如下:

在这里插入图片描述

写起来还是有点小麻烦,要用 3 个 hook 才能实现,寻思着能不能有简单的方式呢

还真被我想出一种,不过没在实际项目中用过,不知道会有啥 BUG,需要用到 2 个 hook

  • useRef 利用其跨生命周期特性保存值,而JS里的值可以为函数,那么可以在父组件初始化,传给子组件去赋值
  • useEffect 子组件重新渲染时赋值,组件销毁时设为空,避免内存泄露

歪纬

import React from "react";
import "./App.css";

type TChildRef = {
    data?: number;
    getValue?: (value: string) => string;
};

type TChildProps = {
    handle: React.MutableRefObject<TChildRef>;
    value: number;
};

const Child: React.FC<TChildProps> = (props) => {
    const { handle, value } = props;
    const [state, setState] = React.useState(value);

    React.useEffect(() => {
        console.log("init");
        handle.current = {
            data: state,
            getValue: (value) => {
                return value.repeat(5);
            },
        };
        return () => {
            console.log("uninit");
            handle.current = {};
        };
    });

    return <h1 onClick={() => setState((state) => state + 1)}>child state:{state}</h1>;
};

const App: React.FC = () => {
    const childRef = React.useRef<TChildRef>({});

    return (
        <div>
            <Child handle={childRef} value={0} />
            <button
                onClick={() => {
                    console.log("data", childRef.current.data);
                    console.log("getValue", childRef.current.getValue?.("123"));
                }}
            >
                call child
            </button>
        </div>
    );
};

export default App;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值