Jacky's blog
首页
  • 学习笔记

    • web
    • android
    • iOS
    • vue
  • 分类
  • 标签
  • 归档
收藏
  • tool
  • algo
  • python
  • java
  • server
  • growth
  • frida
  • blog
  • SP
  • more
GitHub (opens new window)

Jack Yang

编程; 随笔
首页
  • 学习笔记

    • web
    • android
    • iOS
    • vue
  • 分类
  • 标签
  • 归档
收藏
  • tool
  • algo
  • python
  • java
  • server
  • growth
  • frida
  • blog
  • SP
  • more
GitHub (opens new window)
  • web
  • web concept
  • javascript

  • css

  • vue

  • react

    • React 完整学习指南
    • React Hooks 完整指南
    • REACT NATIVE
    • REACT 实用代码片段
      • 父组件传递状态到子组件
        • 通过 props 传递状态
        • 通过 props 传递自定义 context
      • 通过静态方法实现跨组件调用
        • 背景
        • 实现方式
        • 核心原理
        • 1. 静态属性与实例方法的关系
        • 2. 绑定过程
        • 3. TypeScript 类型定义详解
        • 优缺点分析
        • 现代 React Hooks 替代方案
        • 使用建议
    • REACT 高频问题
  • nextjs

  • module

  • web faq
  • web3

  • more

  • 《web》
  • react
Jacky
2024-08-12
目录

REACT 实用代码片段

# 父组件传递状态到子组件

总体来说,整理了三个方法:

  1. 通过 ref 转发,(dom 未挂载场景下,ref 的 current 为 null)
  2. 通过 props 传递状态

# 通过 props 传递状态

父组件

import React, { useState } from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
    const [isActive, setIsActive] = useState(false);

    // 模拟父组件状态的变化
    const toggleActiveState = () => {
        setIsActive(!isActive);
    };

    return (
        <div>
            <button onClick={toggleActiveState}>
                {isActive ? 'Deactivate' : 'Activate'}
            </button>
            <ChildComponent isActive={isActive} />
        </div>
    );
}

export default ParentComponent;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React, { useEffect } from 'react';

function ChildComponent({ isActive }) {
    useEffect(() => {
        if (isActive) {
            console.log('Child Component is active!');
        } else {
            console.log('Child Component is inactive.');
        }
    }, [isActive]);

    return (
        <div>{isActive ? 'The child is active' : 'The child is inactive'}</div>
    );
}

export default ChildComponent;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
代码解释
  • ParentComponent (父组件):

    • 维护一个状态 isActive,并通过按钮点击来切换状态。将 isActive 作为 prop 传递给 ChildComponent
  • ChildComponent (子组件):

    • 接收 isActive 作为 prop,并在 useEffect 中监听 isActive 的变化。每次 isActive 变化时,useEffect 都会触发,并输出相应的信息
如何工作

状态切换: 当你在父组件中点击按钮时,isActive 状态切换,子组件会接收到新的 prop 值并触发 useEffect 挂载后的处理: 即使子组件在父组件状态变化时尚未挂载,子组件挂载后依然会接收到当前的 isActive 值,并根据最新的值执行逻辑 通过这种方式,父组件可以在子组件挂载前就通知其状态,而子组件在挂载后会自动根据接收到的 prop 执行相应的操作

# 通过 props 传递自定义 context

  • 初始化子组件传递 tabContext, 子组件定义可以被父组件调用的方法
  • 父组件在合适的时候通过 tabContext 直接调用目标方法
子组件
export const CommonTabs = (props: CommonTabsProps) => {
    const tabContext = useRef({} as any);

    if (props.tabContext) {
        // 初始化子组件传递 tabContext, 子组件定义可以被父组件调用的方法
        props.tabContext.releasePage = () => {
            releaseSubPage()
        }
        props.tabContext.setPage = (page: number, smoothScroll?: boolean) => {
            setPage(page, smoothScroll)
        }
    }

    return (
      // jsx
    )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
父组件
<CommonTabs
    id={uiConfig.commonTabId}
    length={3}
    tabWidth={(_: number) => 80}
    tabHeight={tabHeight}
    initialPage={Math.max(0, getActiveSubTypePositon())}
    renderPage={function (position: number, params: any) {
        return (
          // jsx
        )
    }}
    renderTab={(i: number, selected: boolean) => {
        return <TabViewV2 index={i} selected={selected}
            tabHeight={tabHeight}
            tabClick={(i: number) => {
                // 父组件在合适的时候通过 tabContext 直接调用目标方法
                tabContext.setPage(i, true)
            }}
        />
    }}
    tabContext={tabContext}
    //...
/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 通过静态方法实现跨组件调用

# 背景

在某些场景下,我们需要在 A 组件调用 B 组件的方法,但又不希望通过 props 层层传递。这时可以使用静态方法的方式来实现跨组件调用。

例如:需要在 A 组件调用 B 组件的一个方法,并传入回调函数,用于监听 B 组件的状态变化(如是否可见)。

# 实现方式

B 组件实现
// @ts-ignore
import * as React from 'react';

export class B extends React.Component {
    // 1. 定义静态属性(类级别)
    static show:
        | ((isVisibleCallback?: (isVisible: boolean) => void) => void)
        | undefined = undefined;

    // 2. 定义实例属性
    showStateCallback: ((isVisible: boolean) => void) | undefined = undefined;

    constructor(props: any) {
        super(props);
        // 3. 将实例方法绑定到静态属性
        B.show = this.show.bind(this);
    }

    // 4. 定义实例方法
    show(showStateCallback?: (isVisible: boolean) => void) {
        // 注入当前的 callback
        this.showStateCallback = showStateCallback;
        // @ts-ignore
        this.setState({ show: true, bottom: 100 });
    }

    close() {
        // @ts-ignore
        this.setState({ show: false });
    }

    // 5. 在状态变化时触发回调
    componentDidUpdate(prevProps: any, prevState: any) {
        // @ts-ignore
        if (this.state.show !== prevState.show) {
            // show state changed and callback
            // @ts-ignore
            this.showStateCallback && this.showStateCallback(this.state.show);
        }
    }

    render() {
        // @ts-ignore
        return <h1>Hello, {this.props.name}!</h1>;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
A 组件调用
// A 组件中直接通过类名调用
B.show?.((isVisible: boolean) => {
    setXXXVisible(isVisible ? 2 : 1);
});
1
2
3
4

# 核心原理

# 1. 静态属性与实例方法的关系

class B extends React.Component {
    // 静态属性(类级别)- 提供外部调用接口
    static show: Function | undefined = undefined;
    
    // 实例方法(实例级别)- 实际执行逻辑
    show(callback?: (isVisible: boolean) => void) {
        // 方法实现
    }
}
1
2
3
4
5
6
7
8
9

# 2. 绑定过程

constructor(props: any) {
    super(props);
    // 将实例方法绑定到静态属性
    B.show = this.show.bind(this);
    //     ↑        ↑
    //   静态属性   实例方法
}
1
2
3
4
5
6
7

为什么需要 .bind(this)?

  • 确保方法内部的 this 始终指向组件实例
  • 解决方法调用时 this 上下文丢失的问题

# 3. TypeScript 类型定义详解

// 完整的类型定义
class B extends React.Component {
    static show: ((isVisibleCallback?: (isVisible: boolean) => void) => void) | undefined = undefined;
}
1
2
3
4

为什么有两个 =>?

  • 第一个 => void:指定 isVisibleCallback 这个回调函数的返回值为 void
  • 第二个 => void:指定 show 方法本身的返回值为 void

类型拆解:

// 等价于
type VisibilityCallback = (isVisible: boolean) => void;
type ShowMethod = (isVisibleCallback?: VisibilityCallback) => void;

class B extends React.Component {
    static show: ShowMethod | undefined = undefined;
}
1
2
3
4
5
6
7

# 优缺点分析

优点:

  1. 解耦组件:外部组件不需要直接持有 B 组件的引用
  2. 调用简单:通过类名直接调用,无需层层传递 props
  3. 状态回调:支持回调函数,可以监听组件状态变化

缺点:

  1. 单例限制:静态属性是类级别的,多个实例会互相覆盖
  2. React 风格:不符合 React 的数据流理念(不推荐大量使用)
  3. 测试困难:静态方法增加了测试的复杂度

# 现代 React Hooks 替代方案

如果使用函数组件和 Hooks,推荐使用以下方式:

// 使用 Context + useImperativeHandle
import { createContext, useContext, useRef, useImperativeHandle, forwardRef } from 'react';

// 1. 创建 Context
const BContext = createContext<{ show: (callback?: (isVisible: boolean) => void) => void } | null>(null);

// 2. B 组件使用 forwardRef + useImperativeHandle
const B = forwardRef((props, ref) => {
    const [isVisible, setIsVisible] = useState(false);
    const callbackRef = useRef<((isVisible: boolean) => void) | undefined>();

    useImperativeHandle(ref, () => ({
        show: (callback?: (isVisible: boolean) => void) => {
            callbackRef.current = callback;
            setIsVisible(true);
        }
    }));

    useEffect(() => {
        callbackRef.current?.(isVisible);
    }, [isVisible]);

    return <div>...</div>;
});

// 3. A 组件调用
function A() {
    const bRef = useRef<{ show: (callback?: (isVisible: boolean) => void) => void }>(null);
    
    const handleClick = () => {
        bRef.current?.show((isVisible) => {
            console.log('B component visibility:', isVisible);
        });
    };

    return (
        <div>
            <button onClick={handleClick}>Show B</button>
            <B ref={bRef} />
        </div>
    );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# 使用建议

  1. 小型项目/简单场景:可以使用静态方法快速实现
  2. 中大型项目:建议使用 Context、状态管理库(Redux、Zustand)或 useImperativeHandle
  3. 多实例场景:避免使用静态方法,改用 ref 转发或 Context
#react#snippet
上次更新: 2025/10/19, 11:29:44
REACT NATIVE
REACT 高频问题

← REACT NATIVE REACT 高频问题→

最近更新
01
npx 使用指南
10-12
02
cursor
09-28
03
inspect
07-20
更多文章>
Theme by Vdoing | Copyright © 2019-2025 Jacky | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式