react 基于 hooks 实现受控组件双向绑定

前言

了解或会 Vue 的朋友都知道,在 Vue 中我们可以通过 v-model 实现 受控组件的数据双向绑定,而在 React 中则需要通过 valueonChange 实现数据的双向绑定,单个还可以接受,如多个呢。

看个例子。

	const [nickName, setNickName] = useState('')
  	const [age, setAge] = useState(null)
  
  	const handleNickNameChange = useCallback((value) => {
	    setNickName(value)
	}, [])
	
	const handleAgeChange = useCallback((value) => {
	    setAge(value)
	}, [])
  
  return (
    <>
      <Input value={nickName} onChange={handleNickNameChange} />
      <Input value={age} onChange={handleAgeChange} />
    </>
  )

根据上面得出结论,如果一个组件内有多个受控组件,那将会向上面一样写很多个。我们能不能封装一下只需要声明变量,不需要声明 set 方法呢。答案是OK的,可以看下面。

Tips:input 的 type 的值为 file 时为非受控组件,原因是因为 type 为 file 时的 value 处于可读状态。

说明

我这里使用的是 React + ts,使用js的话需要删除变量后面的类型声明。

withModel

我这里封装的方法组件为 withModel ,你们可以根据自身命名。

//withModel.tsx

import React, { forwardRef, useMemo, useCallback, useEffect } from 'react'

// 双向绑定工具方法

const withModel = (Component: any) => forwardRef((props, outerRef) => {

    const p =  {
      models: [],
      name: '',
      value: '',
      onChange: (event: any) => {},
      ...props,
    } 
    
    const { models = [], name, value, onChange, ...other } = p;

    const [modelValue, setModelValue] = useMemo(() => models, [models])
    
    const handleChange = useCallback((event: any) => {
          if (setModelValue) {
              const setValue = setModelValue as Function;
              setValue(event.target.value)
          }
        
          if(typeof onChange === 'function') onChange(event)
    }, [onChange])

  return (
    <Component
      {...other}
      ref={outerRef}
      name={name}
      value={modelValue !== undefined ? modelValue : value}
      onChange={handleChange}
    />
  )
})

export default withModel

input.tsx

//input.tsx

import React, { forwardRef } from "react";

import withModel from '../utils/withModel'


type inputProps = React.DetailedHTMLProps<
  React.InputHTMLAttributes<HTMLInputElement>,
  HTMLInputElement
>

const Component = forwardRef<HTMLInputElement, inputProps>((props, outerRef) => {

    const p = {...props};
    let { type } = props;
    
    if(!type) type = 'text';
    
    let element = <input ref={outerRef} {...props} />

    return (
        <>
            {!['checkbox', 'file', 'radio'].includes(type) && element}
        </>
    )
})


Component.displayName = 'Input'

export default withModel(Component );

页面使用

// 页面使用

import React, { useState } from "react";
import Input from "./Input"

export default () => {

    const data = useState('我是输入的内容')

    return (
        <>
            <Input models={data} placeholder="请输入内容" />
            {/*  */}
            <p>{`我是输入的内容: ${data[0]}`}</p>
        </>
    )
}

总结

原理:使用 forwardRef 将当前受控组件的 ref 引用进行传递,通过 withModel 组件方法进行修改。

以上就是 基于 ReactHook 实现受控组件双向绑定的一个过程。

如有不足还请各位指点。

搞定收工。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值