22 React高阶组件

搭建服务端

yarn add express
yarn add nodemon
在server目录下 npm init -y
// 增加dev脚本
  "scripts": {
    "dev": "nodemon ./index.js"
  },

引入

git

HOC

  • High Order Component 高阶组件,是组件的抽象
  • HOC不是React提供的API,高级的设计模式
  • HOC是一个函数,接收一个组件参数,返回一个新组件
  • 普通组件返回的是UI,HOC返回的是一个新组件
  • HOC不能修改参数组件,只能传入组件所需要的props(否则可能会导致参数组价内部的逻辑执行失效)
  • HOC是一个没有副作用的纯函数
  • HOC除了必须填入被包裹的组件参数以外,其余参数根据需求增加
  • HOC不关心数据如何使用,包裹组件不关心数据从哪来,只做渲染
  • HOC和包裹组件直接唯一的契合点是props

代码

完整代码
git

  • index15.jsx
import { fetchListData } from "./index15/front-end/model"
import { listHoc } from './index15/front-end/components/listHoc'

import StudentList from './index15/front-end/components/StudentList'
import TeacherList from './index15/front-end/components/TeacherList'

const StudentListHoc = listHoc(StudentList, fetchListData)
const TeacherListHoc = listHoc(TeacherList, fetchListData)

class App extends React.Component {
    render() {
        return (
            <>
                <StudentListHoc field='student' />
                <TeacherListHoc field='teacher' />
            </>
        )
    }
}
ReactDOM.render(
    <App />,
    document.getElementById('app')
)
  • listHoc .jsx
export function listHoc(WrapperComponent, fetchListData) {
    return class extends React.Component {
        state = {
            listData: []
        }
        remove = (id) => {
            this.setState({
                listData: this.state.listData.filter(item => item.id !== id)
            })
        }

        like = (id) => {
            this.setState({
                listData: this.state.listData.map(item => {
                    if (item.id == id) {
                        item.like = Number(item.like) + 1
                    }
                    return item
                })
            })
        }
        async componentDidMount() {
            const res = await fetchListData(this.props.field)
            this.setState({
                listData: res.data
            })
        }
        render() {
            return (
                <>
                    {
                        this.props.field === 'student' ?
                            <WrapperComponent
                                data={this.state.listData}
                                removeStudent={this.remove}
                            ></WrapperComponent>
                            :
                            <WrapperComponent
                                data={this.state.listData}
                                likeTeacher={this.like}
                            ></WrapperComponent>
                    }
                </>
            )
        }
    }
}

高阶组件横切关注点

  • 横切关注点 → minxins
  • 对参数组件本身的逻辑状态与视图的横向切割
  • 让HOC来完成逻辑和状态的管理
  • 让参数组件来完成视图的渲染
  • 让HOC将数据与逻辑传递到参数组件中,从而完成关注点分离且有机结合的任务

柯里化

  • index.jsx
const StudentListHoc = listHoc(StudentList)(fetchListData)
const TeacherListHoc = listHoc(TeacherList)(fetchListData)
  • listHoc .jsx
export function listHoc(WrapperComponent) {
    return function (fetchListData) {
        return class extends React.Component {
			......
        }
    }
}

还可以在StudentList子组件内部返回listHoc(StudentList)

注意事项

有value就必须有onChange,否则使用defaultValue

  • 使用剩余参数去排除不需要的属性
  • 对“HOC不能修改参数组件”的理解,例如,如下修改参数组件的生命周期函数
  • MyInput.jsx
export default class MyInput extends React.Component {
    componentDidUpdate() {
        console.log('MyInput更新')
    }
    render() {
        return (
            <div>
                <h1>{this.props.inputValue}</h1>
                <p>总计:{this.props.b + this.props.c}</p>
                <input
                    type="text"
                    placeholder="请填写"
                    value={this.props.inputValue}
                    onChange={this.props.valueInput}
                />
            </div>
        )
    }
}
  • InputHoc
export function InputHoc(WrapperComponent) {
    // 注意 如果在这里修重写生命周期函数componentDidUpdate
    // WrapperComponent内的componentDidUpdate将不会被触发
    // WrapperComponent.prototype.componentDidUpdate = () => {
    //     console.log('InputHoc内重写componentDidUpdate')
    // }
    return class InputHocComponent extends React.Component {
        componentDidUpdate() {
            console.log('不重写,都触发')
        }
        state = {
            inputValue: ''
        }
        valueInput = (e) => {
            this.setState({
                inputValue: e.target.value
            })
        }
        render() {
            // 排除参数组件中不需要的属性
            // 注意 剩余参数时变量名必须叫props
            const { a, ...props } = this.props
            return (
                <WrapperComponent
                    inputValue={this.state.inputValue}
                    valueInput={this.valueInput}
                    {...props}
                />
            )
        }
    }
}
  • index.jsx
import MyInput from './index16/front-end/components/MyInput'
import { InputHoc } from './index16/front-end/components/InputHoc'
const MyInputHoc = InputHoc(MyInput)

class App extends React.Component {
    state = {
        a: 1,
        b: 2,
        c: 3
    }
    render() {
        return (
            <>
                <MyInputHoc {...this.state} />
            </>
        )
    }
}
ReactDOM.render(
    <App />,
    document.getElementById('app')
)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • MyInput使用函数组件
export default function MyInput(props) {
    return (
        <div>
            <h1>{props.inputValue}</h1>
            <p>总计:{props.b + props.c}</p>
            <input
                type="text"
                placeholder="请填写"
                value={props.inputValue}
                onChange={props.valueInput}
            />
        </div>
    )
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值