REACT 实用代码片段
# 父组件传递状态到子组件
总体来说,整理了三个方法:
- 通过 ref 转发,(dom 未挂载场景下,ref 的 current 为 null)
- 通过 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
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
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
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
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
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 组件中直接通过类名调用
B.show?.((isVisible: boolean) => {
setXXXVisible(isVisible ? 2 : 1);
});
1
2
3
4
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
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
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
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
2
3
4
5
6
7
# 优缺点分析
优点:
- 解耦组件:外部组件不需要直接持有 B 组件的引用
- 调用简单:通过类名直接调用,无需层层传递 props
- 状态回调:支持回调函数,可以监听组件状态变化
缺点:
- 单例限制:静态属性是类级别的,多个实例会互相覆盖
- React 风格:不符合 React 的数据流理念(不推荐大量使用)
- 测试困难:静态方法增加了测试的复杂度
# 现代 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
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
# 使用建议
- 小型项目/简单场景:可以使用静态方法快速实现
- 中大型项目:建议使用 Context、状态管理库(Redux、Zustand)或
useImperativeHandle - 多实例场景:避免使用静态方法,改用 ref 转发或 Context
上次更新: 2025/10/19, 11:29:44