likes
comments
collection
share

受控组件与非受控组件的实践与展示前言 在前端开发中,我们经常用到用到输入的一些组件,这些组件大致可分为两大类,受控组件和

作者站长头像
站长
· 阅读数 31

前言

在前端开发中,我们经常用到用到输入的一些组件,这些组件大致可分为两大类,受控组件非受控组件 ,用于处理一些数据的输入。

介绍

受控组件

  • 组件的状态是可控制的
  • 更新状态是同步的,每次更新数据就会重新渲染一次视图
  • 代码举一个例子
const Index = () => {
    const [value, setValue] = useState<string>("");
    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const v = e.target.value;       
        setValue(v); // 重新渲染数据
    };
    return <>
    <p>{value}</p>
    <input type="text" value={value} onChange={handleChange}  />
    </>;
}

受控组件

  • 组件的状态是不可控制的,可能导致数据不一致
  • 更新状态是异步的
  • 代码举一个例子
const Index = () => {
    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const v = e.target.value;       
        console.log("🚀 ~ handleChange ~ v", v);
    };
    return <>
    <p>{value}</p>
    <input defaultValue={'1111111'} onChange={handleChange} />
    </>;
}

实现

通过上面的例子我们大致知道了什么是受控组件和非受控组件。要是我们在实际开发中使用组件是受控 组件还是用非受控组件嘞,这是一个值得思考的问题,还需要结合实际情况使用。不过毫无疑问的是,封装一个输入的组件,我们还是得将其两者都要兼顾,比如说,Antd Design就是这样做的,在组件的参数传递的时候都有defaultValuevalue两个可选值。

我们可以通过传入的参数defaultValuevalue去判断是否为受控组件非受控组件

举个例子:

// 封装useControllableValue
import { SetStateAction, useCallback, useRef, useState } from "react";

type Props<T> = {
    defaultValue?: T;
    value?: T;
    onChange?: (e: T) => void;
}

function useControllableValue<T>(props: Props<T>): [T, (v: SetStateAction<T>) => void] {
    const { value, defaultValue, onChange } = props;
    const isControllable = value !== undefined;
    const newValue = value ?? defaultValue ?? '';

    const [_, setState] = useState<T>(newValue as T); // 确保在状态变化时正确地触发重新渲染,同时在需要时访问最新的值。
    
    const ref = useRef<T>(newValue as T);

    if (isControllable) {
        ref.current = value as T;
    }

    useCallback(() => {
        if (isControllable) {
            setState(value as T);
        }
    }, [value, isControllable]);

    const setValue = (v: SetStateAction<T>) => {
        const t = typeof v === 'function' ? (v as Function)(ref.current) : v;

        if (!isControllable) {
            ref.current = t;
            setState(t);
        }

        onChange && onChange(t);
    };

    return [ref.current, setValue];
}

export {useControllableValue};

// 封装一个Input组件
import { useControllableValue } from "./useControllableValue";

type Props = {
    defaultValue?: string;
    value?: string;
    onChange?: (e: string) => void;
    // onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
}

// 非受控组件
// const Index = ( props: Props ) => {
//     const { defaultValue, onChange } = props;
//     return <input type="text" defaultValue={defaultValue} onChange={onChange}  />;
// }

// 受控组件
// const Index = ( props: Props ) => {
//     const { defaultValue, value, onChange } = props;
//     return <input type="text" defaultValue={defaultValue} value={value} onChange={onChange}  />;
// }
const Index = ( props: Props ) => {
    const { defaultValue } = props;
    const [value, setValue] = useControllableValue<string>(props);
    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const v = e.target.value;       
        setValue(v);
    };
    return <>
    <input type="text" defaultValue={defaultValue} value={value} onChange={handleChange}  />
    </>;
}

效果

受控组件

function App() {

 
    const [value, setValue] = useState<string>('hello world');
    const handleChange = (e: string) => {
        console.log("🚀 ~ handleChange ~ e:", e)
        setValue(e);
    };
    return <div>
        <Input value={value} onChange={handleChange} />
    </div>;
}

export default App;

受控组件与非受控组件的实践与展示前言 在前端开发中,我们经常用到用到输入的一些组件,这些组件大致可分为两大类,受控组件和

非受控组件

function App() {
    const handleChange = (e: string) => {
        console.log("🚀 ~ handleChange ~ e:", e)
        setValue(e);
    };
    return <div>
        <Input defalutValue={"hello"} onChange={handleChange} />
    </div>;
}

export default App;

受控组件与非受控组件的实践与展示前言 在前端开发中,我们经常用到用到输入的一些组件,这些组件大致可分为两大类,受控组件和

结语

在封装一个hook函数useControllableValue的时候,大家可以用ahooks中的useControllableValue相关源码,也可以自己手写,主要就是通过defaultValuevalue这个值去判断是否为受控组件,然后去获取最新的值将传递出去。

转载自:https://juejin.cn/post/7425803259442397223
评论
请登录