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

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

  • 前言
  • 示例
    • 组件使用
    • Form组件
    • FormItem 组件
    • Input 组件

前言

学完@我不是外星人的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 属性,用于让
    识别
  • 声明 onChange 方法,通过 props 提供给,作为改变 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

你可能感兴趣的:(React,学习笔记,node.js,javascript,es6)