前言
了解或会Vue
的朋友都知道,在Vue
中我们可以通过v-model
实现受控组件的数据双向绑定,而在React
中则需要通过value
和onChange
实现数据的双向绑定,单个还可以接受,如多个呢。
看个例子。
const[nickName,setNickName]=useState('')const[age,setAge]=useState(null)consthandleNickNameChange=useCallback((value)=>{setNickName(value)},[])consthandleAgeChange=useCallback((value)=>{setAge(value)},[])return(<><Inputvalue={nickName}onChange={handleNickNameChange}/><Inputvalue={age}onChange={handleAgeChange}/></>)
根据上面得出结论,如果一个组件内有多个受控组件,那将会向上面一样写很多个。我们能不能封装一下只需要声明变量,不需要声明set
方法呢。答案是OK的,可以看下面。
Tips:input的type的值为file时为非受控组件,原因是因为type为file时的value处于可读状态。
说明
我这里使用的是React
ts
,使用js
的话需要删除变量后面的类型声明。
withModel
我这里封装的方法组件为withModel
,你们可以根据自身命名。
//withModel.tsximportReact,{forwardRef,useMemo,useCallback,useEffect}from'react'//双向绑定工具方法constwithModel=(Component:any)=>forwardRef((props,outerRef)=>{constp={models:[],name:'',value:'',onChange:(event:any)=>{},...props,}const{models=[],name,value,onChange,...other}=p;const[modelValue,setModelValue]=useMemo(()=>models,[models])consthandleChange=useCallback((event:any)=>{if(setModelValue){constsetValue=setModelValueasFunction;setValue(event.target.value)}if(typeofonChange==='function')onChange(event)},[onChange])return(<Component{...other}ref={outerRef}name={name}value={modelValue!==undefined?modelValue:value}onChange={handleChange}/>)})exportdefaultwithModel
input.tsx
//input.tsximportReact,{forwardRef}from"react";importwithModelfrom'../utils/withModel'typeinputProps=React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>,HTMLInputElement>constComponent=forwardRef<HTMLInputElement,inputProps>((props,outerRef)=>{constp={...props};let{type}=props;if(!type)type='text';letelement=<inputref={outerRef}{...props}/>return(<>{!['checkbox','file','radio'].includes(type)&&element}</>)})Component.displayName='Input'exportdefaultwithModel(Component);
页面使用
//页面使用importReact,{useState}from"react";importInputfrom"./Input"exportdefault()=>{constdata=useState('我是输入的内容')return(<><Inputmodels={data}placeholder="请输入内容"/>{/**/}<p>{`我是输入的内容:${data[0]}`}</p></>)}
总结
原理:使用forwardRef
将当前受控组件的ref
引用进行传递,通过withModel
组件方法进行修改。
如有不足还请各位指点。
搞定收工。