组件通信
在函数组件中通过接收props参数可以直接获取传入的状态
在类组件中使用this.props获取
props可以传递任意状态、jsx语法、函数等等
import React from "react";
import ReactDOM from 'react-dom'
// const Hello = props => {
// return (
// <div>
// <h1>props: {props.name}</h1>
// </div>
// )
// }
// class Hello extends React.Component {
// render() {
// return (
// <div>
// <h1>props: { this.props.name }</h1>
// </div>
// )
// }
// }
class Hello extends React.Component {
constructor(props) {
super(props);
console.log(props)
}
render() {
return (
<div>
<h1>props: { this.props.name }</h1>
</div>
)
}
}
ReactDOM.render(<Hello name='jack' age={19}/>,document.getElementById('root'))
父传子
import React from "react";
import ReactDOM from 'react-dom'
class Parent extends React.Component {
state = {
lastName:'王'
}
render() {
return (
<div className='parent'>
父组件
<Child name={ this.state.lastName }/>
</div>
)
}
}
const Child = (props) => {
return (
<div className='child'>
<p>子组件,接收到父组件的数据:{ props.name }</p>
</div>
)
}
ReactDOM.render(<Parent/>,document.getElementById('root'))
子传父
子传父需要在父组件定义一个方法,再将这个方法传给子组件,子组件调用这个方法,同时把状态作为实参传入父组件的方法,父组件就可以拿到传入的状态了
import React from "react";
import ReactDOM from 'react-dom'
class Parent extends React.Component {
getChildMsg = data => {
alert(data)
}
render() {
return (
<div className='parent'>
父组件
<Child getMsg={ this.getChildMsg }/>
</div>
)
}
}
class Child extends React.Component {
state = {
msg:'Battle cruise'
}
handleClick = () => {
this.props.getMsg(this.state.msg)
}
render() {
return (
<div className='child'>
子组件:<button onClick={this.handleClick}>点我,给父组件传递数据</button>
</div>
)
}
}
ReactDOM.render(<Parent/>,document.getElementById('root'))
兄弟通信
兄弟通信是使用的状态提升方法,通过共同的父组件作为中间交换状态。
import React from "react";
import ReactDOM from 'react-dom'
class Counter extends React.Component {
state = {
count:0
}
onIncrement = () => {
this.setState({
count:this.state.count + 1
})
}
render() {
return (
<div>
<Child1 count={this.state.count}/>
<Child2 onIncrement={this.onIncrement}/>
</div>
)
}
}
const Child1 = (props) => {
return <h1>计数器:{props.count}</h1>
}
const Child2 = (props) => {
return <button onClick={()=>props.onIncrement()}>+1</button>
}
ReactDOM.render(<Counter/>,document.getElementById('root'))
Context通信
本质上是使用的props的children方法实现的,通过React.createContext()方法获取Provider 和 Consumer 。给传出数据的组件渲染函数外套上并传入value数据。
在传入数据的组件渲染函数里使用,在内部使用函数形参接受传入的数据并使用
import React from "react";
import ReactDOM from 'react-dom'
const { Provider ,Consumer } = React.createContext()
class App extends React.Component {
render() {
return (
<Provider value='pink'>
<div className='app'>
<Node/>
</div>
</Provider>
)
}
}
const Node = prop => {
return (
<div className='node'>
<SubNode/>
</div>
)
}
const SubNode = props => {
return (
<div className='subnode'>
<Child/>
</div>
)
}
const Child = props => {
return (
<div className='child'>
<Consumer>
{
data => <span>我是子节点 -- { data }</span>
}
</Consumer>
我是子节点
</div>
)
}
ReactDOM.render(<App/>,document.getElementById('root'))
props中children
render函数中组件双标签中传入内容,组件可以使用props.children或者this.props.children获取传入的内容
import React from "react";
import ReactDOM from 'react-dom'
// const App = props => {
// console.log(props)
// return (
// <div>
// <h1>组件标签的子节点:</h1>
// {props.children}
// </div>
// )
// }
//
// ReactDOM.render(<App>我是子节点</App>,document.getElementById('root'))
const Test = () => <button>我是button组件</button>
const App = props => {
console.log(props)
return (
<div>
<h1>组件标签的子节点:</h1>
{props.children}
</div>
)
}
ReactDOM.render(
<App>
<Test/>
</App>,
document.getElementById('root'))
组件生命周期
创建时
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count:0
}
console.log('生命周期钩子函数:constructor')
}
componentDidMount() {
const title = document.getElementById('title')
console.log(title)
console.log('生命周期钩子函数:componentDidMount')
}
render() {
console.log('生命周期钩子函数:render')
return (
<div>
<h1 id='title'>统计豆豆被打的次数:</h1>
<button id='btn'>打豆豆</button>
</div>
)
}
}
ReactDOM.render(<App/>,document.getElementById('root'))
更新时
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count:0
}
}
handleClick = () => {
// this.setState({
// count:this.state.count + 1
// })
// 强制更新
this.forceUpdate()
}
render() {
console.log('生命周期钩子函数:render')
return (
<div>
<Counter count={this.state.count}/>
<button onClick={this.handleClick}>打豆豆</button>
</div>
)
}
}
class Counter extends React.Component {
render() {
console.log('子组件生命周期钩子函数:render')
return (
<h1>统计豆豆被打的次数:{this.props.count}</h1>
)
}
}
ReactDOM.render(<App/>,document.getElementById('root'))
更新时注意:
如果在更新时的钩子函数componentDidUpdate()中调用setState()方法,必须在条件判断中,否则会导致递归更新,报错!!
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count:0
}
}
handleClick = () => {
this.setState({
count:this.state.count + 1
})
// 强制更新
// this.forceUpdate()
}
render() {
return (`在这里插入代码片`
<div>
<Counter count={this.state.count}/>
<button onClick={this.handleClick}>打豆豆</button>
</div>
)
}
}
class Counter extends React.Component {
render() {
console.log('子组件-生命周期钩子函数:render')
return (
<h1 id='title'>统计豆豆被打的次数:{this.props.count}</h1>
)
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log('子组件-生命周期钩子函数:componentDidUpdate')
// 如果要调用setState()更新状态,必须要放在判断条件中,否则会导致递归更新报错!!
if (prevProps.count !== this.props.count){
this.setState({})
}
}
}
ReactDOM.render(<App/>,document.getElementById('root'))
组件复用
render props模式组件复用
import React from "react";
import ReactDOM from 'react-dom'
import img from './images/cat.png'
class Mouse extends React.Component {
state = {
x:0,
y:0
}
handleMouseMove = (e) => {
this.setState({
x:e.clientX,
y:e.clientY
})
}
componentDidMount() {
window.addEventListener('mousemove',this.handleMouseMove)
}
render() {
return this.props.render(this.state)
}
}
class App extends React.Component {
render() {
return (
<div>
<h1>render props 模式</h1>
<Mouse render={(mouse)=><p>鼠标当前位置:{mouse.x},{mouse.y}</p>}/>
<Mouse render={(mouse)=>{
return <img src={ img } alt="cat" style={{
position:'absolute',
top:mouse.y - 64,
left:mouse.x - 64,
}}/>
}}/>
</div>
);
}
}
ReactDOM.render(<App/>,document.getElementById('root'))
使用children进行优化:
import React from "react";
import ReactDOM from 'react-dom'
import img from './images/cat.png'
class Mouse extends React.Component {
state = {
x:0,
y:0
}
handleMouseMove = (e) => {
this.setState({
x:e.clientX,
y:e.clientY
})
}
componentDidMount() {
window.addEventListener('mousemove',this.handleMouseMove)
}
// 组件卸载时 移除事件绑定
componentWillUnmount() {
window.removeEventListener('mousemove',this.handleMouseMove)
}
render() {
return this.props.children(this.state)
}
}
class App extends React.Component {
render() {
return (
<div>
<h1>render props 模式</h1>
<Mouse>{
(mouse)=>{
return (
<p>鼠标当前位置:{mouse.x},{mouse.y}</p>
)
}
}</Mouse>
<Mouse>
{
(mouse)=>{
return <img src={ img } alt="cat" style={{
position:'absolute',
top:mouse.y - 64,
left:mouse.x - 64,
}}/>
}
}
</Mouse>
</div>
);
}
}
ReactDOM.render(<App/>,document.getElementById('root'))
高阶组件
高阶组件就是利用通用逻辑的组件在内部对可能存在的同时使用该逻辑的组件进行一次封装,再把它们返回出去,但是不负责渲染,而需要渲染时直接使用二次封装后的组件标签便可以实现对组件的共用。
b站这个视频讲解的不错,可以看看》》》》
import React from 'react'
import ReactDOM from 'react-dom'
import img from './images/cat.png'
//创建高阶组件
function withMouse(WrappedComponent) {
class Mouse extends React.Component {
state = {
x: 0,
y: 0
}
handleMouseMove = (e) => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
componentDidMount() {
window.addEventListener('mousemove', this.handleMouseMove)
}
componentWillUnmount() {
window.removeEventListener('mousemove', this.handleMouseMove)
}
render() {
return (
<WrappedComponent {...this.state} {...this.props}/>
// 这块对porps也进行展开是为了后续组件之间可能存在的通信
);
}
}
// 设置组件名字,方便devtools调试用
Mouse.displayName = `withMouse${getDisplayName(WrappedComponent)}`
return Mouse
}
function getDisplayName(WrappedComponent){
return WrappedComponent.displayName || WrappedComponent.name || 'Component'
}
const Position = props => (
<p>
鼠标当前位置:(x:{props.x},y:{props.y})
</p>
)
const Cat = props => (
<img src={img} alt="cat" style={{
position: 'absolute',
top: props.y - 64,
left: props.x - 64
}}/>
)
const MousePosition = withMouse(Position)
const CatPosition = withMouse(Cat)
class App extends React.Component {
render() {
return (
<div>
<h1>高阶组件</h1>
<MousePosition/>
<CatPosition/>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('root'))