React study notes - Simple form encapsulation using React Hooks
foreword
After learning @我不是外星人's React Advanced Practice Guide, I learned the basic use of props, implicit injection of props, form nesting principles, etc. Use the knowledge of React Hooks learned to make simple changes to the demo given in the original text
I hope that through this practical demo, everyone can learn:
- basic use of props
- Learn to operate props.children, implicitly inject props
- Master the principle of form nesting (the reality is more complicated than this)
example
Component usage
/**
* 组件使用
* ./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 component
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
- To filter out elements other than
FormItem
the element , how do you knowFormItem
if it is? Here is a way to teach you a way to bind a static property to a function component or class component to prove its identity, and then you can whenprops.children
traversing OnReact element
thetype
attribute (class or function component itself), verify the identity. In this demo project, binddisplayName
the attribute to prove the identity of the component. - To clone
FormItem
a node , mixinhandleChange
the method that changes the form cell item and the value of the form into .value
props
FormItem component
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
Be sure to binddisplayName
the property to allow<Form>
the recognition<FormItem />
- Declare
onChange
the method ,props
provided to by<Input>
, as the callback function forvalue
changing . FormItem
Filter out other elementsinput
except .
Input component
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
- bind
displayName
idinput
. input DOM
Element, boundonChange
method , for passingvalue
.