组件化:把一个项目拆成一个一个的组件,为了便与开发与维护
组件之间互相独立且封闭,一般而言,每个组件只能使用自己的数据(组件状态私有)。
如果组件之间相互传参怎么办? 那么就要考虑组件之间的通讯。
props能够实现传递数据和接受数据。
作用:接收其他组件传递的数据
传递:给组件标签添加属性,就表示给组件传递数据
接收:分为函数组件和类组件
props
this.props
// 函数组件通过props获取
function Hi(props) {
return <div>{props.name}</div>
}
...
...
const VNode = (
<div>
<Hi name={'Tricia'}></Hi>
</div>
)
// class 组件需要通过 this.props 来获取
class Hello extends Component {
render() {
return <div>接收到的数据:{this.props.age}</div>
}
}
...
...
const VNode = (
<div>
<Hello name="jack" age={19} />
</div>
)
{}
将父组件的数据传递给子组件,数据是单向流,子组件中是只读的!
// 定义一个父组件
class Father extends React.Component {
// 父组件在state中提供数据
state = {
fName: '朗道',
}
render() {
return (
<>
<div>
<p>father</p>
{/* 父组件数据通过子组件标签传递给子组件 */}
<Son fName={this.state.fName}></Son>
</div>
</>
)
}
}
子组件中通过 this.props.属性名
接收父组件中传递的数据
import { Component } from 'react'
class Son extends Component {
render() {
return (
<>
{/* 子组件通过this.props接收父组件传过来的数据并渲染 */}
<p>Son : {this.props.fName}</p>
</>
)
}
}
export default Son
父传子也可以在内容里面传,用JSX。子组件接受时使用 this.props.children
import React, { Component } from 'react'
import ReactDom from 'react-dom'
class AppSon extends Component {
render() {
console.log(this.props)
return (
<>
<h2>我是App的儿子</h2>
<div>
{this.props.name}
{this.props.age}
{/* 用children来接受 */}
{this.props.children}
</div>
</>
)
}
}
class App extends Component {
render() {
return (
<>
<h1>我是App</h1>
<AppSon name={'停云'} age={18098}>
{/* 父传子也可以在此处传递 */}
{<p>hi,我是内容</p>}
</AppSon>
</>
)
}
}
ReactDom.createRoot(document.querySelector('#root')).render(<App></App>)
import React, { Component } from 'react'
import ReactDom from 'react-dom/client'
// 子传父本质是父组件传递给子组件一个方法,子组件通过调这个方法来向父组件传参。
class AppSon extends Component {
render() {
return (
<>
<h2>我是App的儿子</h2>
<span>{this.props.name}</span>
<button onClick={() => this.props.editName(this.props.name)}>
点击执行父组件的方法
</button>
</>
)
}
}
class App extends Component {
state = {
name: '冷面小青龙',
}
editName = (val) => {
console.log(val)
this.setState({
name: val === '丹恒' ? '冷面小青龙' : '丹恒',
})
}
render() {
return (
<>
<h1>我是App</h1>
<AppSon name={this.state.name} editName={this.editName}></AppSon>
</>
)
}
}
ReactDom.createRoot(document.querySelector('#root')).render(<App></App>)
回调函数不能用普通函数,因为this指向的问题,如果是普通函数那么谁调用this就指向谁。这个函数是被this.props调用的,所以this指向的是父组件传递过去的参数
class App extends Component {
state = {
name: '冷面小青龙',
}
editName() {
// 错误写法
// 注意⚠️:这里不能用普通函数,因为this指向的问题,如果是普通函数那么谁调用this就指向谁。这个函数是被this.props调用的,所以this指向的是父组件传递过去的参数
console.log(this)
}
render() {
return (
<>
<h1>我是App</h1>
<AppSon name={this.state.name} editName={this.editName}></AppSon>
</>
)
}
}
核心思想:状态提升
公共父组件职责:
要互相通讯的两个子组件只需通过props接受或者操作状态。说白了就是。父传子 + 子传父
import React, { Component } from 'react'
import ReactDOM from 'react-dom/client'
import Son1 from './Son1'
import Son2 from './Son2'
export default class App extends Component {
state = {
num: '123',
}
editNum = (n) => {
this.setState({
num: +this.state.num + n,
})
}
render() {
return (
<>
<div>App</div>
{/* 通过子传父改变num值 */}
<Son1 editNum={this.editNum}></Son1>
{/* 父传子得到Son1的num 值 */}
<Son2 num={this.state.num}></Son2>
</>
)
}
}
ReactDOM.createRoot(document.querySelector('#root')).render(<App></App>)
context: 上下文,可以理解为是一个范围,在这个范围内的所有组件都可以跨级通讯。
context.jsx
// 公共组件:提供Provider, Consumer这两个组件
// 1. 导入createcontext方法
import { createContext } from 'react'
// 2. 调用方法得到两个组件 Provider, Consumer
const Context = createContext()
export default Context
index.js
import React, { Component } from 'react'
import ReactDOM from 'react-dom/client'
import GrandPa from './GrandPa'
import Context from './Context/context'
const { Provider } = Context
export default class App extends Component {
state = {
num: '云浮将军景元元',
age: 109776,
}
render() {
return (
// 使用Provider组件包裹根组件,并要提供value
// 若要提供多个属性,可以写成对象格式
<Provider value={{ name: this.state.num, age: this.state.age }}>
<div>
<h1>App</h1>
<GrandPa></GrandPa>
</div>
</Provider>
)
}
}
ReactDOM.createRoot(document.querySelector('#root')).render(<App></App>)
在任意一个组件中均可使用共享的数据,例如Father.jsx
import React, { Component } from 'react'
import Son from './Son'
import Context from './Context/context'
const { Consumer } = Context
export default class Father extends Component {
render() {
return (
<Consumer>
{/* 接收state 需要将DOM放入插值中,并用箭头函数返回 */}
{(obj) => (
<div style={{ border: '2px solid #333', margin: '10px' }}>
Father -- {obj.name}
<Son></Son>
</div>
)}
</Consumer>
)
}
}
在Son.jsx组件中去修改状态
import React, { Component } from 'react'
import Context from './Context/context'
const { Consumer } = Context
export default class Son extends Component {
render() {
return (
<Consumer>
{(obj) => (
<div style={{ border: '2px solid #333', margin: '10px' }}>
Son -- {obj.age}岁
<button onClick={() => obj.editAge(5)}>增加➕</button>
</div>
)}
</Consumer>
)
}
}