day-03
React组件通信
父传子
父组件通过自定义属性传递数据
子组件,类组件通过this.props接收数据,函数组件通过props接收数据
import React, { Component } from 'react'
import Son from './Son'
import Son2 from './Son2'
export default class Father extends Component {
state = {
username: 'zs',
age: 18,
}
render() {
return (
<div>
Father
<hr></hr>
{}
<Son uname={this.state.username} age={this.state.age}></Son>
{}
<Son2 uname={this.state.username}></Son2>
</div>
)
}
}
import React, { Component } from 'react'
export default class Son extends Component {
render() {
return (
<div>
son
<p>用户名:{this.props.uname}</p>
<p>年龄:{this.props.age}</p>
</div>
)
}
}
import React from 'react'
export default function Son2({ uname }) {
return (
<div>
Son2
{}
<h4>{uname}</h4>
</div>
)
}
注意事项
目标
- 掌握 props 的注意点。
- 知道什么是单向数据流。
内容
-
Props 是只读的,不能修改。 -
单向数据流,也叫做:自上而下的数据流。 a,当父组件中的数据更新时,子组件接收到的数据也会自动更新。 b,但不能反过来,例如子组件直接去修改父组件的数据。 c,类比:就像瀑布的水一样只能从上往下流动,并且,当上游的水变浑浊,下游的水也会受到影响。 -
可以给组件传递任意类型的数据,例如数字、字符串、布尔、对象、函数、JSX 等。 -
使用类组件时,如果写了构造函数,应该在 constructor 中接收 props,并将 props 传递给 super,否则无法在构造函数中使用 this.props。
子传父
目标
能够将子组件的数据传递给父组件。
内容
a,父组件通过属性传递一个回调函数。
b,子组件调用传递过来的回调函数,并将要传递的数据作为回调函数的实参。
c,父组件在回调函数中通过形参接收传递过来的数据并做相应操作。
案例:
父组件
import React, { Component } from 'react'
import Child from '../child/index'
import './index.css'
class Parent extends Component {
state = {
list: [
{
id: 1,
name: '超级好吃的棒棒糖',
price: 18.8,
info: '开业大酬宾,全场8折',
},
{
id: 2,
name: '超级好吃的大鸡腿',
price: 34.2,
info: '开业大酬宾,全场8折',
},
{
id: 3,
name: '超级无敌的冰激凌',
price: 14.2,
info: '开业大酬宾,全场8折',
},
],
}
changePrice = (id, price) => {
this.setState({
list: this.state.list.map((item) => {
if (item.id === id) {
let p = (item.price - price).toFixed(2)
if (p <= 0) {
p = 0
}
return {
...item,
price: +p,
}
} else {
return item
}
}),
})
}
render() {
const { list } = this.state
return (
<div className="parent">
{list.map((item) => (
<Child key={item.id} {...item} changePrice={this.changePrice}></Child>
))}
</div>
)
}
}
export default Parent
子组件
import React, { Component } from 'react'
import './index.css'
export default class Child extends Component {
render() {
const { name, price, info, id } = this.props
const p = Math.floor(Math.random() * 3 + 1)
return (
<div className="child">
<h3 className="title">标题:{name}</h3>
<p className="price">价格:{price}</p>
<p className="product">{info}</p>
<button
onClick={() => {
this.props.changePrice(id, p)
}}
>
砍一刀
</button>
</div>
)
}
}
兄弟通信
目标
能够将子组件的数据传递给父组件。
内容
需求:点击 A 中的按钮,修改 B 中的数据 count。
步骤
- 准备 A、B 兄弟组件。
- 把需要操作的 B 组件中的数据 count 提升到公共的父组件里面。
- 父组件提供数据和操作数据的方法。
- 把数据传递给 B 组件,把操作数据的方法传递给 A 组件。
这种方法也叫状态提升。
Context
目标
通过 Context 实现跨级组件通讯。
内容
- 之前通信的局限性。
- 远房亲戚关系(也就是两个组件之间间隔较远),可以使用 Context。
步骤
- 祖先组件通过
React.crateContext() 创建 Context 并导出。 - 祖先组件通过
<Context.Provider> 配合 value 属性提供数据。 - 后代组件通过
<Context.Consumer> 配合函数获取数据。 - 优化:提取
React.crateContext() 到单独的文件里面。
代码
App.jsx
import React, { Component, createContext } from 'react'
import A from './A'
export const context = createContext()
export default class App extends Component {
state = {
money: 8888,
}
changeMoney = (n) => {
this.setState({
money: this.state.money + n,
})
}
render() {
return (
<context.Provider
value={{
money: this.state.money,
changeMoney: this.changeMoney,
}}
>
App
<hr />
<A />
</context.Provider>
)
}
}
A.jsx
import React, { Component } from 'react'
import B from './B'
export default class A extends Component {
render() {
return (
<div>
A
<hr />
<B />
</div>
)
}
}
B.jsx
import React, { Component } from 'react'
import { context } from './App'
export default class B extends Component {
render() {
return (
<context.Consumer>
{(value) => {
return (
<div>
<h1>{value.money}</h1>
<button onClick={() => value.changeMoney(8)}>changeMoney</button>
</div>
)
}}
</context.Consumer>
)
}
}
获取context数据的另一种方式:
- 在context中默认提供一个对象,祖先元素不使用
context.Provider - 在B组件中声明一个静态属性
contextType 等于Context 对象 - 然后就可以通过
this.context 拿到传递过来的数据
|