React 学习笔记 - 使用React Hooks进行简单的表单封装

React 学习笔记 - 使用React Hooks进行简单的表单封装

前言

学完@我不是外星人的React进阶实践指南,了解了props的基本使用、隐式注入props、表单嵌套原理等。利用所学React Hooks知识对原文给出的demo进行了简单改动

希望通过这实践 demo 让大家学习到:

  1. props 基本使用
  2. 学会操作 props.children ,隐式注入 props
  3. 掌握表单嵌套原理(现实情况要比这个复杂)

示例

组件使用

/**
 *	组件使用
 *	./src/pages/App/App.js
 */
import React, {
    
     useRef } from 'react'
import Form from '../../components/Form/Form'
import FormItem from '../../components/FormItem/FormItem'
import Input from '../../components/Input/Input'

export default function App(){
    
    
	const form = useRef(null)
	const submit =()=>{
    
    
	  /* 表单提交 */
	  form.current.submitForm((formValue)=>{
    
    
	      console.log(formValue)
	  })
	}
	const reset = ()=>{
    
    
	  /* 表单重置 */
	  form.current.resetForm()
	}
	return (
	    <div>
	        <Form ref={
    
     form } >
	            <FormItem name="name" label="我是"  >
	                <Input/>
	            </FormItem>
	            <FormItem name="mes" label="我想对大家说"  >
	                <Input/>
	            </FormItem>
	            <input  placeholder="不需要的input" />
	            <Input/>
	        </Form>
	        <button className="searchbtn"  onClick={
    
     submit } >提交</button>
	        <button className="concellbtn" onClick={
    
     reset } >重置</button>
	    </div>
	)
}

Form组件

import React, {
    
     useImperativeHandle, useState } from 'react'

const Form = React.forwardRef((props, ref)=>{
    
    
  const [formData,setFormData] = useState({
    
    })
  const submitForm = (cb) => {
    
    
    cb({
    
    ...formData})
  }
  const resetForm = () => {
    
    
    let formDataTemp = {
    
    ...formData}
    Object.keys(formDataTemp).forEach(item=>{
    
    
      formDataTemp[item] = ''
    })
    setFormData(formDataTemp)
  }
  const setValue = (name, value) => {
    
    
    setFormData({
    
    
      ...formData,
      [name]:value
    })
  }
  useImperativeHandle(ref,()=>({
    
    
    submitForm,
    resetForm
  }))
  const {
    
     children } = props
  const renderChildren = []
  React.Children.forEach(children, child => {
    
    
    if(child.type.displayName === 'formItem'){
    
    
      const {
    
     name } = child.props
      const Children = React.cloneElement(child ,{
    
    
        key: name,
        handleChange: setValue,
        value: formData[name] || ''
      },child.props.children)
      renderChildren.push(Children)
    }
  })
  return renderChildren
})

Form.displayName = 'form'

export default Form
  • 要过滤掉除了 FormItem 元素之外的其他元素,那么怎么样知道它是不是FormItem,这里教大家一种方法,可以给函数组件或者类组件绑定静态属性来证明它的身份,然后在遍历 props.children 的时候就可以在 React elementtype 属性(类或函数组件本身)上,验证这个身份,在这个 demo 项目,给函数绑定的 displayName 属性,证明组件身份。
  • 要克隆 FormItem 节点,将改变表单单元项的方法 handleChange 和表单的值 value 混入 props 中。

FormItem 组件

import React from 'react'

function FormItem(props) {
    
    
  const {
    
     handleChange, value, name, label, children} = props
  const onChange = (value) => {
    
    
    handleChange(name,value)
  }
  return (
    <div>
      <span>{
    
    label}:</span>
      {
    
    
        React.isValidElement(children) && children.type.displayName === 'input' ?
        React.cloneElement(children,{
    
    onChange, value}) : null
      }
    </div>
  )
}

FormItem.displayName = 'formItem'

export default FormItem
  • FormItem一定要绑定 displayName 属性,用于让 <Form> 识别<FormItem />
  • 声明 onChange 方法,通过 props 提供给<Input>,作为改变 value 的回调函数。
  • FormItem过滤掉除了 input 以外的其他元素。

Input 组件

import React from 'react'

function Input(props) {
    
    
  return (
    <input value={
    
    props.value} onChange={
    
    e=>props.onChange(e.target.value)}></input>
  )
}

Input.displayName = 'input'

export default Input
  • 绑定 displayName 标识input
  • input DOM 元素,绑定 onChange 方法,用于传递 value

猜你喜欢

转载自blog.csdn.net/m0_52761633/article/details/123313155