此文项目代码:https://github.com/bei-yang/I-want-to-be-an-architect
码字不易,辛苦点个star,感谢!
引言
此篇文章主要涉及以下内容:
- 函数化组件
Hook
- 上下文的使用
- 设计并实现一个表单组件
学习资源
- Hook
- Context
Hook
Hook
是React 16.8
一个新增项,它可以让你在不编写class
的情况下使用state
以及其他的React
特性。
Hook
的特点:
- 使你在无需修改组件结构的情况下复用状态逻辑
- 可将组件中相互关联的部分拆分成更小的函数,复杂组件将变得更容易理解
- 更简洁、更易理解的代码
准备工作
- 升级
react、react-dom
npm i react react-dom -S
状态钩子-State Hook
- 创建HookTest.js
import React, { useState } from 'react'
export default function HooksTest() {
// useState(initialState),接收初始状态,返回一个状态变量和其更新函数
const [count, setCount] = useState(0)
// 多个状态
const age = useAge();
const [fruit, setFruit] = useState("banana");
const [input, setInput] = useState("");
const [fruits, setFruits] = useState(["apple", "banana"]);
return (
点击了{count}次
年龄:{age ? age : 'loading...'}
选择的水果:{fruit}
setInput(e.target.value)}
/>
{fruits.map(f => (
- setFruit(f)}>
{f}
))}
)
}
副作用钩子-Effect Hook
userEffect
就是一个Effect Hook
,给函数组件增加了操作副作用的能力。它跟class
组件中的componentDidMount、componentDidUpdate
和componentWillUnmount
具有相同的用途,只不过被合并成了一个api
。
- 更新HooksTest.js
import React, { useState, useEffect } from 'react'
// 副作用钩子会在每次渲染时都执行
// 如果仅打算执行一次,传递第二个参数为[]
// componentDidMount
useEffect(() => {
// api调用
console.log("api调用");
}, []);
useEffect(() => {
// Update the documnet title using the browser api
document.title = `点击了${count}次`
})
自定义钩子-Custom Hook
自定义Hook
是一个函数,其名称以use
开头,函数内部可以调用其他的Hook
。
function useAge() {
const [age, setAge] = useState(0)
useEffect(() => {
setTimeout(() => {
setAge(20)
}, 2000)
})
return age
}
// 使用
const age = useAge()
年龄{age ? age : 'loading...'}
其他Hook
useContext
,useReducer
,useCallback
,useMemo
组件跨层级通信-Context
上下文提供一种不需要每层设置props
就能跨多级组件传递数据的方式
Context相关API
- React.createContext
- Context.Provider
- Class.contextType
- Context.Consumer
基本用法
创建文件contextText.js
- 创建上下文
const MyContext = React.createContext();
- 提供上下文
const { Provider } = MyContext
export default function App() {
return (
)
}
- 消费上下文
function Child3(props) {
return {props.foo}
}
export default function App() {
return (
{value => }
)
}
组件设计与实现
表单组件实现
import React from 'react'
import { Input, Button } from 'antd'
import { log } from 'util'
/*
创建一个高阶组件:
1、扩展现有表单
2、事件处理
3、数据收集
4、校验1
*/
function kFromCreate(Comp) {
return class extends React.Component {
constructor(props) {
super(props)
this.options = {}
this.state = {}
}
handleChange = e => {
const { name, value } = e.target
console.log(name, value)
this.setState({ [name]: value }, () => {
// 确保值发生变化再校验
this.validateField(name)
})
}
validateField = field => {
// 1.获取校验规则
const rules = this.options[field].rules
// 任意一项失败则返回false
const ret = !rules.some(rule => {
if (rule.required) {
if (!this.state[field]) {
// 校验失败
this.setState({
[field + 'Message']: rule.message
})
return true
}
}
})
if (ret) {
this.setState({
[field + 'Message']: ''
})
}
return ret
}
// 校验所有字段
validate = cb => {
const rets = Object.keys(this.options).map(field =>
this.validateField(field)
)
const ret = rets.every(v => v === true)
cb(ret, this.state)
}
// 创建input包装器
getFieldDec = (field, option) => {
// 保存当前输入项配置
this.options[field] = option
return InputComp => (
{React.cloneElement(InputComp, {
name: field,
value: this.state[field] || '',
onChange: this.handleChange
})}
{/* 校验错误信息 */}
{this.state[field + 'Message'] && (
{this.state[field + 'Message']}
)}
)
}
render() {
return (
)
}
}
}
@kFromCreate
class KForm extends React.Component {
onSubmit = () => {
console.log('submit')
// 校验所有项
this.props.validate((isValid, data) => {
if (isValid) {
//提交登录
console.log('denglu:', data)
// 后续登录逻辑
} else {
alert('校验失败')
}
})
}
render() {
const { getFieldDec } = this.props
return (
{getFieldDec('uname', {
rules: [{ required: true, message: '用户名必填' }]
})()}
{getFieldDec('pwd', {
rules: [{ required: true, message: '密码必填' }]
})()}
)
}
}
export default KForm
你的赞是我前进的动力
求赞,求评论,求分享...