React 是 Facebook 创造的 JavaScript 库。虽然在 React 中处理数据显得有点复杂,但其实并没有那么棘手。最近我总结了三种在 React 中进行数据处理的方法:
- 使用 Props 从父组件传递数据到子组件
- 使用回调函数从子组件传递数据到父组件
- 非父子组件之间传递数据:
- 结合 Props 和回调函数
- 使用 Redux 传递数据
- 使用 React Context API 传递数据
这篇文章中主要总结了这些实现方式,新手可以从中纵览全局。
使用 Props 从父组件传递数据到子组件
假设我们的目录结构如下所示:
App
└── Parent
├── Child1
└── Child2
这是 React 中最简单也是最基础的数据流向。
class Parent extends React.Component {
state = { data : "Hello World" }
render() {
return (
<div>
<Child1/> // 无数据传递
<Child2 dataFromParent = {this.state.data} />
</div>
);
}
}
// 没有强制要求必须传递 state 中的值,通过 var 或者 const 定义的变量也可以从父组件传递给子组件
在子组件中,可以非常简单地使用 this.props.dataFromParent
(只是一个通过 props 传递的变量) 来获取到从父组件传递过来的数据。
class Child2 extends React.Component {
render() {
return (
<div>
The data from parent is:{this.props.dataFromParent}
</div>
);
}
}
使用回调函数从子组件传递数据给父组件
如果我要从 Child1 子组件中传递信息——“美女,最近还好吗?” 给父组件,应该怎么做呢?为了实现这个目的,需要按照以下步骤进行操作:
第一步:在父组件中定义一个有参数的回调函数
第二步:将该回调函数作为 Props 传递到 Child1 子组件
class Parent extends React.Component {
state = { message: "" }
callbackFunction = (childData) => {
this.setState({message: childData})
},
render() {
return (
<div>
<Child1 parentCallback = {this.callbackFunction}/>
<p> {this.state.message} </p>
</div>
);
}
}
第三步:在子组件中,通过调用 this.props.callback(dataToParent)
将数据 dataToParent
传递给父组件
class Child1 extends React.Component{
sendData = () => {
this.props.parentCallback("美女,最近还好吗?");
},
render() {
//在想传递信息给父组件的任意时刻调用 sendData 方法
}
};
非父子组件之间传递数据
当我还是一个初学者的时候,选择哪种方式进行非父子组件间通讯对我来说是一个难题。现在我知道有以下三种方式,并且每种方式都有自己的优缺点。
方式1:结合 Props 和回调函数
这种方式不适用复杂的组件树,因为这将有一大部分进行数据传递的代码要写,而且需要中间层进行数据的传递,虽然可能它们并不需要该数据。
方式2:使用 Redux 传递数据
方式3:使用 React Context API 传递数据
现在有很多关于为什么 React 增强了 Context API 以及在何场景下哪种方式更优的文章。以下是两篇推荐:
React Context API — A Replacement for Redux?
我使用过这种方式,相比 Redux,我更倾向于使用该方式。
Context API 的最大优势是:这种方式使开发者从 “Prop 深渊”中解放出来。(Props 深渊是指传递数据到子组件中。主要的思路是函数式编程,不断地将参数传递给下一个函数)
建设我们有以下的组件树,想要从 Child1 中传递信息“SSup brother?”给组件 Child2。
App
├── Child1
└── Child2
第一步:为两个子组件创建一个 Provider
这个 Provider 管理 state 并返回一个 contextObject.Provider
组件。
第二步:在 Provider 组件中,使用 props 传递 state 和回调函数
export const MContext = React.createContext();
// 导出 context 对象
class MyProvider extends Component {
state = {message: ""}
render() {
return (
<MContext.Provider value={
{
state: this.state,
setMessage: (value) => this.setState({message: value })}}>
{this.props.children} // 这里显示所有的子组件都可以访问全局的 store
</MContext.Provider>)
}
}
provider 是所有子组件共享的(一个全局的store,保存了所有 state 和一个操作这些 state 的回调函数)。任何需要这些状态的组件都需要先和 provider 打交道。
(a) 在 Child1 中通过 provider 中的 setMessage 处理信息
(b) 在 Child2 中通过 provider 获取信息
第三步:将 MyProvider 当做 Child1 和 Child2 两个组件的父组件
class App extends React.Component {
render() {
return (
<div>
<MyProvider>
<div className="App">
<Child1/>
<Child2/>
</div>
</MyProvider>
</div>
);
}
}
第四步:Child1 和 Child2 都是 Provider 的消费者,进而都需要通过使用 Consumer 标签来与 Provider 打交道。
import MContext
class Child1 extends React.Component {
render() {
return (
<div>
<Mcontext.Consumer>
{(context) => (
<button onClick={()=>{context.setMessage("New Arrival")}}>Send</button>
)}
</Mcontext.Consumer>
</div>
)
}
}
Child2 中如何接收这些数据呢?
也是用 Consumer 标签与 Provider 打交道。
import MContext
class Child2 extends React.Component {
render() {
return (
<div>
<Mcontext.Consumer>
{(context) => (
<p>{context.state.message}}</p>
)}
</Mcontext.Consumer>
</div>
)
}
}
希望上面的描述比较清晰的解释了如何在 React 中进行大量组件的数据传递。