React第三章 组件写法和HOC

117 阅读5分钟

第一节、傻瓜组件 & 聪明组件 区别

1、傻瓜组件也叫展示组件: 负责根据props显示页面信息

2、聪明组件也叫容器组件: 负责数据的获取、处理、组合、下传给展示组件

3、容器组件+展示组件的优势

3.1、逻辑和展示相分离

3.2、提高组件复用性

3.3、提高组件可用性和可阅读性

3.4、便于测试+后续维护

第二节、函数式组件(没有Hook前的)基础使用

1、函数式组件是一种无状态组件,是为了创建纯展示组件,这种组件只根据传入的props来展示,不涉及state状态的操作。

2、组件不会被实例化,整体渲染性能得到提升。

3、组件不能访问this对象。

4、组件无法访问生命周期的方法。

5、无状态组件只能访问传入的props,同样的props会得到同样的渲染结果,不会有副作用

6、官方:大部分的React代码中,大多数组件被写成无状态组件,通过简单组合构建成其他组件。通过多个简单合并成一个大应用的设计模式被提倡。

7、具体写法如下:

import React from 'react'

export default function Button(props) {
    return <div>
        <p>函数式组件</p>
        <IsLogo isLogo={props.isLogo} btnText={props.btnText}></IsLogo>
    </div>
}

// 这种写法直供组件内部使用,不提供给外部
function IsLogo({ isLogo, btnText }) {
    let result = <button>{btnText}</button>
    if (isLogo) {
        result = <button>&yen;{btnText}</button>
    }
    return result;
}

第三节、class组件基础使用

1、React.createClass是react刚开始推荐的创建组件写法(es6前),现在基本上看不到了。

2、React.Component是以ES6的形式来创建react组件的,是React目前极为推荐的创建有状态组件的方式

2.1、里面可以写生命周期、状态、构造函数等

2.2、具体展示如下

import React, { Component } from 'React';

export default class ConditionLoop extends Component {
	render(){
		return <div>
    
                </div>
	}
}

3、React Hooks 更为推荐的函数式变成。以后会更多

第四节、高阶组件初体验

1、高阶组件-HOC(Higher-Order Components)。

2、高阶组件是为了提高组件的复用率而出现的,抽离出具有相同逻辑或者相同展示的组件。

3、高阶组件其实是一个函数,接收一个组件作为入参,返回一个新的组件。返回的这个组件可以对属性进行包装,或者重写部分生命周期。

4、高阶组件默认命名规则:以with开头

// 创建 withLearnReact的高阶组件。传递一个组件进去,返回一个新的组件NewComponent
const withLearnReact = (Comp) => {
    const NewComponent = (props) => {
        const extendName = "leranReact高阶组件";
        return <Comp {...props} name={extendName} />
    }
    return NewComponent
}
export default withLearnReact(XXX);

5、LearnReact.js

import React, { Component } from 'react'

// 1、使用函数式组件
// function LearnReact(props) {
//     return (
//         <div>
//             <p>{props.title}</p>
//             <p>传入的值:{props.name}</p>
//             <p>原始的值:learnReact原始组件</p>
//         </div>
//     )
// }
// const withLearnReact = (Comp) => {
//     const NewComponent = (props) => {
//         const extendName = "leranReact高阶组件";
//         return <Comp {...props} name={extendName} />
//     }
//     return NewComponent
// }

// 2、使用class组件
class LearnReact extends Component {
    render() {
        return (
            <div>
                <p>{this.props.title}</p>
                <p>传入的值:{this.props.name}</p>
                <p>原始的值:learnReact原始组件</p>
            </div>
        )
    }
}
const withLearnReact = (Comp) => {
    class newComponent extends Component {
        render() {
            const extendName = "learnReact高阶组件";
            return <Comp {...this.props} name={extendName}></Comp>
        }
    }
    return newComponent;
}

export default withLearnReact(LearnReact);

App.js

import LearnReact from './hoc/LearnReact';
...
<LearnReact title="高阶组件-标题"></LearnReact>

第五节、高阶组件链式调用

1、使用情况如下:

1.1、编写一个高阶组件属性的添加。

1.2、编写一个高阶组件重写生命周期。

1.3、然后两个高阶组件进行链式调用。

2、Chain.js

import React, { Component } from 'react'

class LearnReact extends Component {
    render() {
        return (
            <div>
                <p>{this.props.title}</p>
                <p>传入的值:{this.props.name}</p>
                <p>原始的值:learnReact原始组件</p>
            </div>
        )
    }
}
const withLearnReact1 = (Comp)=>{
    class newCompoent extends Component {
        componentDidMount(){
            console.log('w1','didMount');
        }
        render() {
            const extendName = "learnReact高阶组件";
            return (
                <Comp {...this.props} name={extendName}></Comp>
            )
        }
    }
    return newCompoent
}
const withLearnReact2 = (Comp)=>{
    class newCompoent extends Component {
        componentDidMount(){
            console.log('w2','didMount');
        }
        render() {
            return (
                <Comp {...this.props}></Comp>
            )
        }
    }
    return newCompoent
}
export default withLearnReact2(withLearnReact1(LearnReact));

第六节、高阶组件装饰器写法

1、替换链式调用,ES7专门出现这种装饰器的语法,解决链式调用的不美观。(java里面是叫注解

2、安装支持装饰器语法的babel插件。

2.1、 npm install --save-dev @babel/plugin-proposal-decorators 

  or  yarn add --dev @babel/plugin-proposal-decorators

2.2、更改配置文件根目录下的 config-overrides.js

const { override, fixBabelImports, addBabelPlugin } = require('customize-cra');
module.exports = override(
    // 配置antd按需加载
    fixBabelImports('import', {
        libraryName: 'antd',
        libraryDirectory: 'es',
        style: 'css',
    }),
    // 配置支持高阶组件装饰器写法
    addBabelPlugin(["@babel/plugin-proposal-decorators", { "legacy": true }])
);

3、Decorator.js

import React, { Component } from 'react'

const withLearnReact2 = (Comp) => {
    class newCompoent extends Component {
        componentDidMount() {
            console.log('WD2', 'didMount');
        }
        render() {
            return (
                <Comp {...this.props}></Comp>
            )
        }
    }
    return newCompoent
}
const withLearnReact1 = (Comp) => {
    class newCompoent extends Component {
        componentDidMount() {
            console.log('WD1', 'didMount');
        }
        render() {
            const extendName = "learnReact高阶组件";
            return (
                <Comp {...this.props} name={extendName}></Comp>
            )
        }
    }
    return newCompoent
}
@withLearnReact2
@withLearnReact1
class LearnReact extends Component {
    render() {
        return (
            <div>
                <p>{this.props.title}</p>
                <p>传入的值:{this.props.name}</p>
                <p>原始的值:learnReact原始组件</p>
            </div>
        )
    }
}
export default LearnReact;

第七节、高阶组件通信-context

1、vue 中的组件通信中的一种:provide/inject ,这种借鉴于React的context上下文中的2个对象:

1.1、Provider : 提供者。

1.2、Consumer :消费者。

1.3、解决问题就是:多层组件嵌套的props、跨层级使用数据。

2、使用context可以避免通过中间元素传递props,context的设计目的是为了共享对于一个组件树而言的的 “全局数据”。

3、不使用context的代码需要多层使用{...props}。

import React, { Component } from 'react'
const store = {
    name: '周芷若',
    age: 23,
}

// 不使用context
function Info(props) {
    return (
        <div>
            <p>{props.title}</p>
            <p>姓名:{props.name}</p>
            <p>年龄:{props.age}</p>
        </div>
    )
}
function ToolBar(props) {
    return (
        <Info {...props}></Info>
    )
}
export default class UseContext extends Component {
    render() {
        return (
            <div>
                <ToolBar {...this.props} name={store.name} age={store.age}></ToolBar>
            </div>
        )
    }
}

4、使用context

4.1写法一

import React, { Component } from 'react'
const store = {
    name: '周芷若',
    age: 23,
}
// 使用context
const context = React.createContext();
class Info extends Component {
    render() {
        return (
            <context.Consumer>{
                store => {
                    return (
                        <div>
                            <p>{store.title}</p>
                            <p>姓名:{store.name}</p>
                            <p>年龄:{store.age}</p>
                        </div>
                    )
                }
            }</context.Consumer>
        )
    }
}

class ToolBar extends Component {
    render() {
        return (
            <Info></Info>
        )
    }
}
export default class UseContext extends Component {
    render() {
        return (
            <div>
                <context.Provider value={store}>
                    <ToolBar></ToolBar>
                </context.Provider>
            </div>
        )
    }
}

\

4.2写法二 + 合并props

import React, { Component } from 'react'
const store = {
    name: '周芷若',
    age: 23,
}
// 使用context
const { Provider, Consumer } = React.createContext();
class Info extends Component {
    render() {
        return (
            <Consumer>{
                store => {
                    return (
                        <div>
                            <p>{store.title}</p>
                            <p>姓名:{store.name}</p>
                            <p>年龄:{store.age}</p>
                        </div>
                    )
                }
            }</Consumer>
        )
    }
}
function ToolBar() {
    return <Info />
}
export default class UseContext extends Component {
    render() {
        return (
            <div>
                <Provider value={{ ...store, ...this.props }}>
                    <ToolBar />
                </Provider>
            </div>
        )
    }
}