前言
学完@我不是外星人的React进阶实践指南,了解了props的基本使用、隐式注入props、表单嵌套原理等。利用所学React Hooks知识对原文给出的demo进行了简单改动
希望通过这实践 demo 让大家学习到:
- props 基本使用
- 学会操作 props.children ,隐式注入 props
- 掌握表单嵌套原理(现实情况要比这个复杂)
示例
组件使用
/**
* 组件使用
* ./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 element
的type
属性(类或函数组件本身)上,验证这个身份,在这个 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
。