父子组价的通信
- 父传子通过
props
, 组件的props只读,组件本身不能修改他的props
所有 React 组件(类组件和函数组件)都必须像纯函数一样保护它们的 props 不被更改。
<User name="kobe" age=40 />
在User中获取值
class User extends Component {
constructor(props) {
super(props);
}
render() {
const { name, age } = this.props;
return (
<div>
<h3>name: {name}</h3>
<h3>age: {age}</h3>
</div>
)
}
}
- 子传父通过函数
假设组件UserInfo
中有Avatar
组件,更换头像完成时候需要在Profile中更新用户信息。
class Avatar extends Component {
constructor(props) {
super(props);
}
updateAvatar = () => {
// 1\选择图片
// 2\post图片
// 3\成功之后获取对应的url
const url = "新的url";
// 回调给父组件,反向传值
this.props.changeAvatar(url);
}
render() {
const { avatarUrl, name } = this.props;
return (
<img className="Avatar"
src={avatarUrl}
alt={name}
onClick={e => this.updateAvatar()}
/>
)
}
}
class UserInfo extends Component {
render() {
const user = { name: 'kobe', age: 40 };
const avatarInfo = {
avatarUrl: 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1600940289325&di=55075e8388eb0072621f930b87f4d12e&imgtype=0&src=http%3A%2F%2Fb.hiphotos.baidu.com%2Fzhidao%2Fwh%3D450%2C600%2Fsign%3D3b480bceb07eca80125031e3a413bbeb%2F4d086e061d950a7b8b51e3290ad162d9f3d3c9f3.jpg',
alt: "kobe",
avatarOnClick: (newUrl) => {
// 接收到子组件Avatar的值
console.log(newUrl);
}
};
return (
<div>
<h3>用户名:{user.name}</h3>
<h3>年龄:{user.age}</h3>
<Avatar
avatarUrl={avatarInfo.avatarUrl}
alt={avatarInfo.alt}
changeAvatar={avatarInfo.avatarOnClick} />
</div>
)
}
}
跨组件之间的通信
通过props正向传值,一层层的传递。通过回调函数一层层的反向传递。
正向传值的时候可以不用一个个属性分开写,可以合并写,比较方便一点
// Profile是一个类组件
// 通过属性一个个传值
<Profile name="kobe" age={40} />;
// props对象全部在一起传递
const userInfo = {name:'kobe', age: 40};
<Profile {...userInfo} />
通过Context的方式跨组件传递
创建Context,createContext
函数传入一个初始值
const initInfo = {name:'kobe', age:40};
const UserContext = React.createContext(initInfo);
子孙组件需要被Conetxt.Provider
组件包裹
const user = {nickName:'kobe', age:42};// 实际传递的值
<UserContext.Provider value={user}>
<Profile />
</UserContext.Provider>
Profile
组件中还包括子组件ProfileHeader
组件,在ProfileHeader
中获取实际传过来的值
给ProfileHeader组件设置ContextType属性
ProfileHeader.contextType = UserContext;
然后才能在ProfileHeader
中获取到值
class ProfileHeader extends Component {
render() {
return (
<div>
<h3>用户名: {this.context.name}</h3>
<h3>级别:{this.context.age}</h3>
</div>
)
}
}
也可在Context
中包含function
类型的数据,这样就可以实现反向传值了,跟父子反向传值一样。
函数组件使用Context通信
Context.Consumer必须作为一个单独的节点
import React, { Component } from 'react'
const UserContext = React.createContext({
nickname: 'aaaa',
level: 0
});
const ThemeContext = React.createContext({
color: 'red'
})
function ProfileHeader() {
return (
<UserContext.Consumer>
{
val => {
return (
<ThemeContext.Consumer>
{
theme => {
return (
<div>
<h3 style={{ color: theme.color }}>用户:{val.nickname}</h3>
<h3>级别:{val.level}</h3>
</div>
)
}
}
</ThemeContext.Consumer>
)
}
}
</UserContext.Consumer>
)
}
function Profile() {
return (
<div>
<ProfileHeader />
<ul>
<li>设置1</li>
<li>设置2</li>
<li>设置3</li>
<li>设置4</li>
<li>设置5</li>
</ul>
</div>
)
}
export default class App extends Component {
render() {
const user = {
nickname: 'kobe',
level: 9999
};
return (
<div>
<UserContext.Provider value={user}>
<ThemeContext.Provider value={{ 'color': 'red' }}>
<Profile />
</ThemeContext.Provider>
</UserContext.Provider>
</div>
)
}
}