受控组件:表单元素能够受到state里面的数据进行控制
将state里面的数据绑定给表单元素,给表单元素注册onChange事件,通过onChange将表单元素的值同步给state
非受控组件:通过创建ref,从而获取到表单元素,通过表单元素的value方式获取到输入框的值
父传子:通过属性绑定的形式进行传递,子组件通过props形式进行接收
子传父:实际上是通过父组件给子组件传了一个回调函数,子组件通过调用父组件的回调函数,通过传参的形式进行传递
兄弟组件:将传递的数据和修改数据的方法,提到就近的父组件上面,通过父组件传值,传递数据和方法,传递给对应的兄弟组件
跨组件传值:创建一个context,通过provider和consumer分别进行传值和接收值
通过props-types这个插件来实现props传递值的类型校验
在constructor中:在constructor中不允许调用setState,也就是在组件挂载之前不允许调用setState
render生命周期函数中能否调用setState?
一旦调用setState就会重新调用render,调用render就又调用了setState,进入递归循环
componentDidMount:可以调用的
componentDidMount发送请求比较合适
render、componentDidUpdate
(子组件没有用到父组件的数据)当父组件的数据发生变化,子组件会重新触发render吗?
会重新触发
componentWillUnmount
可以清除当前组件的定时器或者注册的页面滚动事件等等无意义的事件也将其卸载
通过render-props模式封装组件主要是来封装状态和方法,至于组件的ui结构,就应该哪里用传递不同的结构
通过属性绑定的形式传递一个函数返回自定义的结构
再通过调用该函数将数据传递给父组件上面
定义Mouse组件来封装公共的鼠标的位置和鼠标移动的逻辑
import React from 'react'
import ReactDOM from 'react-dom'
// 封装鼠标信息组件
// 该组件封装复用的数据和逻辑
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 () {
// 渲染的ui结构不能写死
return null
}
}
class App extends React.Component {
render () {
return (
<div>
<Mouse />
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
动态渲染ui结构
import React from 'react'
import ReactDOM from 'react-dom'
// 封装鼠标信息组件
// 该组件封装复用的数据和逻辑
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 () {
// 渲染的ui结构不能写死
return this.props.renderUi(this.state.x,this.state.y)
}
}
class App extends React.Component {
render () {
return (
<div>
{/* 这里在使用的时候希望显示文字 */}
<Mouse renderUi={
(x,y)=>{
return <div>鼠标的位置:x:{x},y:{y}</div>
}
} />
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
也是为了复用组件的状态和操作状态的逻辑
封装一个高阶组件:封装一个高阶组件实际就是封装一个函数,函数内部提供一个组件,用来复用状态和操作状态的逻辑,至于显示的ui结构,通过函数调用传递一个ui组件,将传递的ui组件进行显示,并且把数据暴漏给这个ui组件。最终这个函数返回一个新的组件
定义一个方法,该方法返回一个组件,返回的组件用来复用数据和逻辑
import React from 'react'
import ReactDOM from 'react-dom'
function withMouse() {
class Mouse extends React.Component {
state = {
x: 0,
y: 0
}
onMouseMove = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
componentDidMount() {
window.addEventListener('mousemove',this.onMouseMove)
}
render () {
return <div>鼠标</div>
}
}
return Mouse
}
const Mouse = withMouse()
ReactDOM.render(<Mouse/>, document.getElementById('root'))
因为结构写死了,所以定义一个想渲染的结构组件,并传递给mouse组件进行展示
import React from 'react'
import ReactDOM from 'react-dom'
function withMouse(WrapperComponent) {
class Mouse extends React.Component {
state = {
x: 0,
y: 0
}
onMouseMove = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
componentDidMount() {
window.addEventListener('mousemove',this.onMouseMove)
}
render () {
return <WrapperComponent />
}
}
return Mouse
}
const Position = ()=>(
<div>
鼠标的位置:
</div>
)
const Mouse = withMouse(Position)
ReactDOM.render(<Mouse/>, document.getElementById('root'))
最后一步再将数据传到要显示的组件上
import React from 'react'
import ReactDOM from 'react-dom'
function withMouse(WrapperComponent) {
class Mouse extends React.Component {
state = {
x: 0,
y: 0
}
onMouseMove = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
componentDidMount() {
window.addEventListener('mousemove',this.onMouseMove)
}
render () {
return <WrapperComponent x={this.state.x} y={this.state.y}/>
}
}
return Mouse
}
const Position = (props)=>(
<div>
鼠标的位置:{props.x},{props.y}
</div>
)
const Mouse = withMouse(Position)
ReactDOM.render(<Mouse/>, document.getElementById('root'))
setState更新数据是异步的,如果想多个setState进行依赖,需要将setState修改成传一个回调函数的形式
this.setState(()=>{
return {}
})
this.setState(()=>{
return {}
})
jsx还是转换为React.createElement的形式了,最终React.createElement又转换为一个React元素,也就是虚拟dom
父组件调用setState的时候,父组件本身,及其所有的子组件的render都会重新执行,但是render重新执行不代表页面会重新渲染,render这个阶段会进行虚拟dom的比较的,然后进行按需更新
可以通过shouldComponentUpdate这个生命周期函数返回true或者false从而决定是否执行render
本质上就是一个JS对象,用来描述你希望在屏幕上看到的内容
虚拟dom高效更新执行过程
因为我们把组件传递给了Route组件,Route组件内部通过this.props.component获取到传递进去的组件,获取到之后将该组件进行展示,并且为该组件传递了history等属性
// js伪代码
// 伪代码
class Route extends React.Component {
state = {
history:{
push: function(){}
}
}
render() {
const View = this.props.component
return
}
}