受控和非受控组件-高阶函数-高级组件和应用
受控组件与非受控组件
在 React 中,表单元素通常会保存在一些内部的 state,例如表单的值绑定到一个 state。此时,该表单的值的获取和更新都由 React 代码进行控制 (而不是原生的 HTML 表单元素自身控制)。被 React 以这种方式控制取值的表单输入元素就叫做 "受控组件"
;
受控有点类似于 Vue 的双向绑定,但在 React 里你要自己控制表单的值。即绑定了一个 value 属性时,要弄一个 onChange
监听。
非受控组件:表单数据将交由 DOM 节点来处理;开发中受控组件用得比较多。
受控组件例子
模拟一个表单提交:
javascript
handleSubmitClick(event) {
// 1.阻止表单提交的默认行为
event.preventDefault()
// 2.获取到表单数据
console.log(this.state.username)
// 3.发送网络请求
}
handleUsernameChange(event){
this.setState({ username: event.target.value })
}
handlePasswordChange(event){
this.setState({ password: event.target.value })
}
render(){
<div>
<form onSubmit={ e => handleSubmitClick(e)}>
<lable htmlFor="username">
<input
type="text"
id="username"
name="username"
value={username}
onChange={e => handleUsernameChange(e)}
/>
</lable>
<lable htmlFor="password">
<input
type="text"
id="password"
name="password"
value={password}
onChange={e => handlePasswordChange(e)}
/>
</lable>
<button type="submit">提交</button>
</form>
</div>
}
但上面有一个问题是:每添加一个表单项,就要再加一个handle
的方法,有没有什么可以复用的方式,写一个方法就行。
可以使用ES6的一个语法:计算属性名
csharp
handleInputChange(event){
this.setState([event.target.name]: event.target.value)
}
课上还讲了常见的表单元素 checkbox,select 的受控组件例子...重点就是如何维护表单的 state,state 的形式是怎样的(数组、对象等)。
coderwhy老师的学习小建议:
- 先去看官方文档最权威,官方文档没有的话去
StackOverflow
上搜- 代码的一些高级语法不用死记硬背完全背住,因为记不住。自己多写,不会的时候再看之前写过的代码就能熟练用了。分清哪些重要哪些不重要
- 做好学习的规划
高阶组件
高阶函数
满足以下两个条件之一:
- 接受一个或多个函数作为输入;
- 输出一个函数;
filter
、map
、reduce
都是高阶函数。
高阶组件定义
高阶组件(HOC)是以参数为组件,返回值为新组件的函数
高阶组件的作用
对传入的组件进行一层拦截操作,再根据该组件增强得到新组件。
高阶组件的应用
1. Props 的增强
利用高阶组件,可以很方便地添加新的 props
javascript
function enhanceProps(originalComponent, newProps) {
return props => <WrapperCpn {...props} {newProps} />
}
但以上加 props
的做法在开发中很少使用。一个真实的应用场景是利用高阶组件来共享 Context 。可以将 Context
的 value
注入过程写成一个高阶组件,就不用每次都写 ThemeContext.Consumer
javascript
import ThemeContext from "../context/ThemeContext"
function withTheme(originComponent){
return props => {
return (
<ThemeContext.Consumer>
{
value => {
return <OriginComponent {...value} {...props}/>
}
}
</ThemeContext.Consumer>
)
}
}
export default withTheme
这样只需要导出时使用高阶组件再包裹一层,就能取到Context
的 value
值
scala
export class Product extends PureComponent {
render() {
const {color,size} = this.props
return (
<div>Product: {color}</div>
)
}
}
export default withTheme(Product)
2. 渲染判断鉴权
登录鉴权:如果登录成功,展示购物车页面,否则展示登录提示
javascript
function loginAuth(OriginComponent) {
return props => {
const token = localStorage.getItem("token")
if(token) {
return <OriginComponent {...props}/>
} else {
return <h2>请先登录,再跳转到对应页面中</h2>
}
}
}
export default loginAuth
3. 生命周期劫持
4. 之前接触过的高阶组件
- memo
- forwardRef
高阶组件的缺点
- HOC需要在原组件上进行包裹或者嵌套,如果大量使用HOC,将会产生非常多的嵌套
- HOC可以劫持props,在不遵守约定的情况下也可能造成冲突