React 文档
导读与全书目录表:见同目录 01-React 入门:简介·特性与设计范式.md 开头。
react 函数组件通信
父子通信
- 父 -> 子通信(props):父动态属性绑定参数,子函数组件形参为 props
js
// 父组件
function ParentComponent() {
const message = 'Hello from parent';
return <ChildComponent greeting={message} />;
}
// 子组件
function ChildComponent(props) {
return <h1>{props.greeting}</h1>;
}- 子 -> 父通信(回调函数):父动态属性绑定参数值为回调函数,子 props.动态属性 调用
js
// 父组件
function ParentComponent() {
const handleChildData = (data) => {
console.log('Data from child:', data);
};
return <ChildComponent onSendData={handleChildData} />;
}
// 子组件
function ChildComponent(props) {
const sendData = () => {
props.onSendData('Data from child');
};
return <button onClick={sendData}>Send Data</button>;
}- 父 -> 子通信(Refs):获取并操作子组件实例的属性和方法(不推荐):forwardRef + useImperativeHandle
js
import React, { useRef, forwardRef, useImperativeHandle } from 'react';
const ChildComponent = forwardRef((props, ref) => {
const internalRef = useRef();
useImperativeHandle(ref, () => ({
// 暴露给父组件的方法
focus: () => {
internalRef.current.focus();
},
// 暴露给父组件的属性
value: internalRef.current?.value,
}));
return <input ref={internalRef} />;
});
function ParentComponent() {
const childRef = useRef(null);
const handleClick = () => {
childRef.current.focus(); // 调用子组件暴露的方法
console.log(childRef.current.value); // 访问子组件暴露的属性
};
return (
<div>
<ChildComponent ref={childRef} />
<button onClick={handleClick}>聚焦输入框</button>
</div>
);
}后代传参
- 方式一:使用 Context API
js
import React, { useContext } from 'react';
const MyContext = React.createContext();
function App() {
return (
<MyContext.Provider value={{ theme: 'dark' }}>
<Parent />
</MyContext.Provider>
);
}
function Parent() {
return <Child />;
}
function Child() {
const context = useContext(MyContext);
return <div>Theme: {context.theme}</div>;
}- 方式二:使用 props 不断向下传递
公共状态管理
redux & redux-thunk & react-redux
注意
- ref 变化不会触发组件重新渲染
- 函数组件本身没有实例,所以 ref 只能指向 DOM 元素或使用 useImperativeHandle 暴露特定值,如果子组件是类组件,ref 会指向组件实例,可以访问其方法和 state
react 类组件通信
父子通信
- 父 -> 子通信(props):父动态属性绑定参数,子this.props 接收
js
// 父组件
class ParentComponent extends React.Component {
render() {
return <ChildComponent message="Hello from Parent" />;
}
}
// 子组件
class ChildComponent extends React.Component {
render() {
return <div>{this.props.message}</div>;
}
}- 子 -> 父通信(回调函数):父动态属性绑定参数值为回调函数,子 this.props.动态属性 调用
js
// 父组件
class ParentComponent extends React.Component {
handleChildData = (data) => {
console.log('Data from child:', data);
};
render() {
return <ChildComponent sendData={this.handleChildData} />;
}
}
// 子组件
class ChildComponent extends React.Component {
sendDataToParent = () => {
this.props.sendData('Data from Child');
};
render() {
return <button onClick={this.sendDataToParent}>Send Data</button>;
}
}- 父 -> 子通信(Refs):获取并操作子组件实例的属性和方法
js
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.childRef = React.createRef();
}
callChildMethod = () => {
this.childRef.current.childMethod('Data from Parent');
};
render() {
return (
<div>
<button onClick={this.callChildMethod}>Call Child Method</button>
<ChildComponent ref={this.childRef} />
</div>
);
}
}
class ChildComponent extends React.Component {
childMethod = (data) => {
console.log(data);
};
render() {
return <div>Child Component</div>;
}
}后代传参
- 方式一:使用 Context API
js
// 创建Context
const MyContext = React.createContext();
// 提供者组件
class ParentComponent extends React.Component {
state = {
value: 'Context Value'
};
render() {
return (
<MyContext.Provider value={this.state.value}>
<ChildComponent />
</MyContext.Provider>
);
}
}
// 消费者组件
class ChildComponent extends React.Component {
static contextType = MyContext;
render() {
return <div>{this.context}</div>;
}
}- 方式二:使用 props 不断向下传递
公共状态管理
redux & redux-thunk & react-redux
注意
- ref 变化不会触发组件重新渲染
- 函数组件本身没有实例,所以 ref 只能指向 DOM 元素或使用 useImperativeHandle 暴露特定值,如果子组件是类组件,ref 会指向组件实例,可以访问其方法和 state
说说 react 组件通信?表达要点
回答
shell
# 父子通信
父组件 → 子组件:通过 props 传递,父组件把数据 / 方法通过属性传给子组件,子组件用 props 接收
子组件 → 父组件:通过 props 回调函数传递,子组件调用父组件传过来的函数,把数据当参数传回去。
# 跨层级 / 兄弟组件:
方案一:状态提升,把共享状态提到最近公共父组件,由父组件统一管理,再通过 props 分发给子组件。
方案二:Context API 适合多层嵌套、跨很多层级的场景,避免 props 层层传递(props drilling)
方案三:全局复杂状态 通过 Redux / Redux Toolkit 状态管理库,统一维护全局状态
# 其他
ref 通信:父组件获取子组件实例 / DOM,调用子组件方法。
事件总线(event bus):简单项目用发布订阅。EventBus(事件总线,比如监听全局自定义事件)
# 最后
实际开发中,Context API 适合小范围共享(比如主题),Redux 适合大规模全局状态,避免过度使用 Context 导致组件重渲染范围过大。react 插槽
简单内容传递:使用 children
多个命名区域:使用 props 传递 JSX
动态内容或复杂交互:Context API
需要操作子组件:使用 React.Children API
普通插槽(props.children)
js
// 子组件
function Card({ children }) {
return <div className="card">{children}</div>;
}
// 父组件
function App() {
return (
<Card>
<h2>标题</h2>
<p>内容...</p>
</Card>
);
}命名插槽(props 传递)
js
// 子组件
function Layout({ header, sidebar, content }) {
return (
<div className="layout">
<div className="header">{header}</div>
<div className="sidebar">{sidebar}</div>
<div className="content">{content}</div>
</div>
);
}
// 父组件
function App() {
return (
<Layout
header={<h1>网站标题</h1>}
sidebar={<ul><li>菜单1</li><li>菜单2</li></ul>}
content={<p>主要内容区域...</p>}
/>
);
}高级插槽(Context API)
js
const SlotContext = React.createContext();
function SlotProvider({ children, slots }) {
return (
<SlotContext.Provider value={slots}>
{children}
</SlotContext.Provider>
);
}
function Slot({ name }) {
const slots = React.useContext(SlotContext);
return slots[name] || null;
}
function App() {
return (
<SlotProvider slots={{
header: <h1>自定义标题</h1>,
footer: <footer>页脚内容</footer>
}}>
<div>
<Slot name="header" />
<main>主要内容</main>
<Slot name="footer" />
</div>
</SlotProvider>
);
}