React - 高级用法

发布于:2024-04-18 ⋅ 阅读:(25) ⋅ 点赞:(0)

React高级用法

Hooks

Reducer

在这里插入图片描述

useReducer:

import React, { useReducer, useState } from 'react';

const initialState = { count: 0 };

function reducer(state, action) {
    switch (action.type) {
        case 'increment':
            return { count: state.count + 1 }
        case 'decrement':
            return { count: state.count - 1 }
        default:
            console.log('格式不通过!');
    }
}

export default function Reducer() {
    const [number, setNumber] = useState(0);
    
    const [state, dispatch] = useReducer(reducer, initalState);
    
    return (
        <div>
            {state.count}
            <button onClick={() => dispatch({ type: 'increment' })}>+</button>
        </div>
    )
}

Ref

用来指代具体的dom节点

类组件: createRef

import React, { Component } from 'react';

export default class ClassRef extends Component {
    
    constructor(props) {
        super(props);
        
        this.eleRef = createRef();
        this.inputRef = createRef();
    }
    
    handleClick = () => {
        this.inputRef.current.focus();
        console.log(this.eleRef.current);
    }
    
    render() {
        return (
            <div>
                <div id="xxx" ref={this.eleRef}> eleRef </div>
                <input ref={this.inputRef} />
                
                <button onClick={this.handleClick}></button>
            </div>
        )
    }
    
}

函数组件:useRef

import { useRef } from 'react'

export default function FuncRef(props) {
    
    const eleRef = useRef(null);
    const inputRef = useRef(null);
    
    return (
        <div>
            <div id="xxx" ref={this.eleRef}> eleRef </div>
            <input ref={this.inputRef} />
            
            <button onClick={this.handleClick}></button>
        </div>
    )
    
}

Ref转发

类似于vue中 调用子组件的方法 refs.xxx()
在这里插入图片描述

Context上下文

Provider
Comsumer
对应Vue,就是provide,inject
形成一个生成与消费模式的上下文

类组件用法

import { createContext } from 'react';

const ThemeContext = createContext('light');

//    ClassContext.jsx
export default class ClassContext extends Component {
    
    constructor(props) {
        super(props);
        this.state = {
             theme: 'light'
        }
    }

    render() {
        return (
            <div>
                <ThemeContext.Provider
                    value={this.state.theme}
                >
                    <Parent />
                    <button onClick={() => this.setState({ theme: 'light' })}></button>
                </ThemeContext.Provider>
            </div>
        )
    }
}

const Parent = () => {
    return (
        <div>
            <Child1 />
            <Child2 />
        </div>
    )
}

class Child1 extends Component {

    static contextType = ThemeContext;
    render() {
        return (
            <div>
                {this.context}
            </div>
        )
    }
}

class Child2 extends Component {
    render() {
        return (
            <ThemeContext.Consumer>
                {
                    (theme) => (
                        <div>{theme}</div>
                    )
                }
            </ThemeContext.Consumer>
        )
    }
}

History包装(函数组件)

import { useContext, useState, createContext } from 'react';

const ThemeContext = createContext();
const history = window.history;

export default function FuncContext() {
    return (
        <ThemeContext.Provider value={history}>
            <Parent />
        </ThemeContext.Provider>
    )
}

const Parent = () => {
    return <Child />;
}

const withRouter = (Component) => {
    console.log(Component, 'ComponentComponent')
    return () => {
        const nav = useContext(ThemeContext);
        return <Component navigator={nav} />
    }
}

const Child = withRouter((props) => {
    console.log(props);
    return (
        <div>
            <button onClick={() => props.navigator.pushState({}, undefined, 'hello')}>
                hello
            </button>
        </div>
    )
})

高阶函数(HOC)

函数可以作为 参数 和 返回值 。

属性代理

//    CardHoc.jsx
export default function Card({ title, children }) {
    return <div>
        <h2>{ title }</h2>
        {
            children ? 
            <div>{ children }</div> : null
        }    </div>
}

export const withCard = (title) => (Component) => {
    return (props) => {
        const hocStyle = {
            margin: '12px',
            padding: '12px',
            border: '1px solid #ccc',
            borderRadius: '4px'
        }
    
        return <div style={hocStyle}>
            <h2>{title}</h2>
            <Component {....props} />
        </div>
    }
}

//    App.jsx
const Text = ({ num }) => <div>{num}</div>
const CardText = withCard('TextCard')(Text);
<CardText num={100} />

反向继承

import { Component } from 'react';

//    比如我们有一个案例: 我们需要优雅的实现 曝光埋点
/**
 * 有个按钮,我们想知道这个按钮在线上的漏斗转换
 * 每次按钮点击时,记录一个sendLog('my_btn_click'), 其实就是触发一条请求
 * 每次按钮出现时,记录一个sendLog('my_btn_show')
 * 那我的转化,pv('my_btn_click') / pv('my_btn_show')
 */

export default function Extending() {
    return (
        <div><LogIndex /></div>
    )
}

function logProps(logMap) {
    return (WrapperComponent) => {
        const didMount = WrapperComponent.prototype.componentDidMount;
        return class A extends WrapperComponent {
            componentDidMount() {
                if (didMount) {
                    didMount.apply(this);
                }
                
                Object.entries(logMap).forEach([k, v] => {
                    if (document.getElementById(k)) {
                        console.log('事件曝光', v);
                    }
                })
            }
            
            render() {
                return super.render();
            }
        }
    }
}
class Index extends Component {
    render() {
        <div>
            <div id="my_text">这是一个文字信息</div>
            <button id="my_btn">这是一个按钮</button>
        </div>
    }
}

const LogIndex = logProps({
    my_text: 'my_text_show',
    my_btn: 'my_btn_show'
})(Index)

渲染优化

类组件 类似于useMemo

import React, { Component } from 'react'
export default class renderControl extends Compoent {
    
    constructor(props) {
        super(props);
        this.state = {
            num: 0,
            count: 0
        }
        
        this.component = <Child num={this.state.num}>
    }
    
    controlRender = () => {
        const { props } = this.component;
        if (props.num !== this.state.num) {
            return this.component = React.cloneElement(
                this.component,
                { num: this.state.num }
            )
        }
    }
    
    render() {
        
        const { num, count } = this.state;
        
        return <div>
            {this.controlRender()}
            <button onClick={() => this.setState({ num: num + 1 })}>{num}</button>    
            <button onClick={() => this.setState({ count: count + 1 })}>{count}</button>    
        </div>
    }
}

const Child = ({ num }) => {
    console.log('子组件执行');
    return <div>{ num }</div>
}

函数组件 - useMemo

import React, { Component, useState } from 'react'
export default function renderControl() {
    
    const [ num, setNum ] = useState(0);
    const [ count, setCount ] = useState(0);
    
    return <div>
            {useMemo(() => <Child num={num} />, [num])}
            <button onClick={() => this.setState({ num: num + 1 })}>{num}</button>    
            <button onClick={() => this.setState({ count: count + 1 })}>{count}</button>    
        </div>

    
}

const Child = ({ num }) => {
    console.log('子组件执行');
    return <div>{ num }</div>
}


useMemo

函数:返回值进行缓存;
Deps: 依赖项改变了,我就再次执行;

useCallback

函数:函数进行缓存
Deps: 依赖项改变了,我就再次执行;

import React, { useCallback, useState } from 'react';

export default function RenderControl() {
    
    const [num, setNum] = useState(0);
    const [count, setCount] = useState(0);
    
    const handleChange = useCallback(() => {
        setCount(count => count + 1);
    }, [])
    
    return (
        <div>
            <MemoChild onChange={handleChange} />
            <button onClick={() => setNum(num + 1)}>{num}</button>
            <button onClick={() => setCount(count + 1)}>{count}</button>
        </div>
    )
}

const Child = ({ num, onChange }) => {
    console.log('子组件执行');
    return <div>
        <button onClick={() => onChange()}>
            onChange
        </button>
    </div>
}

const MemoChild = React.memo(Child);