React - 高级用法

React高级用法

Hooks

Reducer

useReducer:

js 复制代码
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

js 复制代码
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

js 复制代码
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

形成一个生成与消费模式的上下文

类组件用法

js 复制代码
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包装(函数组件)

js 复制代码
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)

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

属性代理

js 复制代码
//    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} />

反向继承

js 复制代码
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

js 复制代码
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

js 复制代码
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: 依赖项改变了,我就再次执行;

js 复制代码
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);
相关推荐
青皮桔28 分钟前
CSS实现百分比水柱图
前端·css
失落的多巴胺28 分钟前
使用deepseek制作“喝什么奶茶”随机抽签小网页
javascript·css·css3·html5
DataGear31 分钟前
如何在DataGear 5.4.1 中快速制作SQL服务端分页的数据表格看板
javascript·数据库·sql·信息可视化·数据分析·echarts·数据可视化
影子信息33 分钟前
vue 前端动态导入文件 import.meta.glob
前端·javascript·vue.js
青阳流月34 分钟前
1.vue权衡的艺术
前端·vue.js·开源
样子201838 分钟前
Vue3 之dialog弹框简单制作
前端·javascript·vue.js·前端框架·ecmascript
kevin_水滴石穿39 分钟前
Vue 中报错 TypeError: crypto$2.getRandomValues is not a function
前端·javascript·vue.js
翻滚吧键盘39 分钟前
vue文本插值
javascript·vue.js·ecmascript
孤水寒月2 小时前
给自己网站增加一个免费的AI助手,纯HTML
前端·人工智能·html
CoderLiu2 小时前
用这个MCP,只给大模型一个figma链接就能直接导出图片,还能自动压缩上传?
前端·llm·mcp