搭建服务端
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' ?<WrapperComponentdata={this.state.listData}removeStudent={this.remove}></WrapperComponent>:<WrapperComponentdata={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><inputtype="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() {// 排除参数组件中不需要的属性// 注意 剩余参数时变量名必须叫propsconst { a, ...props } = this.propsreturn (<WrapperComponentinputValue={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><inputtype="text"placeholder="请填写"value={props.inputValue}onChange={props.valueInput}/></div>)
}