父到子通信的基础实现
数据从父组件流向子组件主要通过在父组件中使用子组件时将变量绑定到子组件上,在子组件函数上使用参数接收(一般使用props接收父组件传递的参数),父组件到子组件的参数传递时多样的,可以是对象、函数、变量、常量、甚至是JSX都可以传递,下面代码将会一一例举。
const Son = (props) =>{
console.log(props)
// 通过props获取父组件传递的函数、对象、变量、甚至是JSX模板
return <div onClick={props.handleClick}>Click me!
{props.message}
{props.obj.name}
{props.obj.age}
{props.jsx}
</div>
}
function App() {
// 来自父组件的函数
const handleClick = () => {
console.log('Button Clicked!Functon from parent')
}
// 来自父组件的变量
const message = "This is a message from parent"
return (
<div>
<Son
handleClick={handleClick}
message={message}
obj={{name: 'Alice', age: 20}}
jsx={<div>JSX from parent</div>}
></Son>
</div>
);
}
export default App;
从代码中我们可以看多,我们可以向子组件传递父组件定义好的函数、变量、对象以及JSX,通过子组件函数的props变量接收这些传递的数据,props.<变量名>在子组件进行使用,函数可以正常触发,传的message和obj变量都可以正常显示在浏览器,传递过来的JSX也可以直接调用显示在子组件的模板当中。
使用props变量进行父组件到子组件的通信的时候需要注意: 在哪个组件定义的变量就只能在哪里修改,就比如说这里,父组件定义的message变量只能在父组件修改,不能通过props进行修改。
特殊的props属性children
当我们在双标签组件的中间插入其它标签的时候,插入的标签数据就会传递到子组件props的children属性中,下面我们从代码看一下,我们定义了一个Son子组件,在双标签子组件中间插入了一个span标签。
const Son = (props) =>{
console.log(props)
return <div>I am Som component {props.children}</div>
}
function App() {
return (
<div>
<Son>
<span>
this is a span from parent
</span>
</Son>
</div>
);
}
export default App;
从下图我们可以看出,span标签被存储在了props中的children属性中,可以正常在子组件中使用并渲染出来。
综上就是我们父组件向子组件进行通信的基本方式。
子组件向父组件通信
顾名思义,子组件可以将值传递给父组件,这里主要通过在父组件定义一个函数,子组件通过props获取到该函数,通过调用函数并传递参数修改父组件定义的状态变量的值。
下面通过代码分析一下,我们在父组件定义了状态变量message,还有函数handlClick传递的参数的值修改message,我们将函数传递给子组件,并在子组件button元素上绑定该事件,传递与一个参数给父组件。
import { useState } from 'react'
const Son = (props) =>{
return <button onClick={() => props.handleClick('message from Son')}>CLick me to communicate with parent</button>
}
function App() {
// 定义用于接收子组件传递的消息的状态变量
const [message, setMessage] = useState('Initial Message')
// 定义传递给子组件的函数
const handleClick = (mes) => {
setMessage(mes)
}
return (
<div>
<Son handleClick={handleClick}></Son>
<p>{message}</p>
</div>
);
}
export default App;
在初始情况下的页面显示如下:
现在我们点击按钮,可以清楚的看到message的内容改变了,说明子组件成功与父组件进行了通信:
兄弟组件之间进行通信
如图所示,兄弟组件之间进行通信需要由父组件状态变量承担中间人,组件A向父组件传递是是通过父组件定义的函数传递参数实现子向父的通信,而父组件向组件B通信直接通过绑定属性,然后再props中获取即可。
下面我们通过一段代码来解释这个流程,如下所示。
import { useState } from 'react'
// 定义组件A
const A = (props) => {
// 接收父组件传递的函数从而实现通信
return <button onClick={() => props.handleClick('this is a message from A')}>A</button>
}
//定义组件B
const B = (props) => {
// 接收信息并显示信息
return <div>B {props.mes}</div>
}
function App() {
// 定义一个变量,用于实现兄弟组件的通信
const [message, setMessage] = useState('')
// 定义一个函数,用于实现子组件A向父组件传递消息
const handleClick = (mes) => {
setMessage(mes)
}
return (
<div>
<A handleClick={handleClick}></A>
{/* 直接绑定属性实现父组件向子组件传递参数 */}
<B mes={message}></B>
</div>
);
}
export default App;
初始状态截图如下所示:
在点击A按钮后,可以看到信息成功从A组件传递到了B组件。
使用context跨层组件机制实现跨层传递
如果根组件要向深层次的子组件传递信息那无疑是十分麻烦的,那有没有什么比较简单的方法进行跨多层级的通信呢?那就是使用Context机制,分为以下几个步骤:
- 使用createContext创建一个上下文对象Ctx
- 在顶层组件(APP)中通过Ctx.Provider组件提供数据
- 在底层组件中使用React Hook useContext获取数据
import { createContext, useContext } from 'react'
// 1.使用createContext创建一个上下文对象Ctx
const Ctx = createContext()
// B组件下的一级组件,最底层组件
const A = () => {
// 在底层组件中使用React Hook useContext获取数据
const ctx = useContext(Ctx)
return <div>A {ctx.name} {ctx.age}</div>
}
//APP下一级组件组件B
const B = () => {
return <div>B <A></A></div>
}
// 顶级组件APP
function App() {
return (
<div>
{/* 2.在顶层组件使用Ctx.Provider组件传递信息 */}
<Ctx.Provider value={{name: 'Alice', age: 20}}>
<B></B>
</Ctx.Provider>
</div>
);
}
export default App;
浏览器显示结果如下图所示,消息成功在最底层的A组件显示了出来。