react非父子通信
react中非父子通信是通过我们手动创建一个订阅发布者模式实现的
首先定义observer对象 创建两个函数 和一个空数组用来存放订阅的函数 分别为subscribe()每次订阅的话就会把传过来的回调函数push到空的list中 dispatch(data) 每次点击发布的时候把这个函数调用一下 这个函数只需要把上面的list展开把里面的函数执行一遍 这样就在订阅者自身上触发了这个函数
const observer ={
list:[],
//订阅
subscribe(callback){
this.list.push(callback);
},
//发布
dispatch(data){
//遍历数组让每个函数执行
this.list.forEach(item=>{
item(data)
})
}
}
import React, {
Component } from 'react'
const observer ={
list:[],
//订阅
subscribe(callback){
this.list.push(callback);
},
//发布
dispatch(data){
//遍历数组让每个函数执行
this.list.forEach(item=>{
item(data)
})
}
}
class Child1 extends Component{
componentDidMount(){
console.log("componentDidMound","调用订阅方法");
observer.subscribe((data)=>{
console.log("child1的callback",data)
})
}
render(){
return(
<div style={
{
background:"red"}}>
child1--我是微信用户
</div>
)
}
}
class Child3 extends Component{
componentDidMount(){
console.log("componentDidMound","调用订阅方法");
observer.subscribe((data)=>{
console.log("child3的callback",data)
})
}
render(){
return(
<div style={
{
background:"blue"}}>
child1--我是微信用户2
</div>
)
}
}
class Child2 extends Component{
render(){
return(
<div style={
{
background:"yellow"}}>
child2---我是公众号发布者
<button onClick={
this.handclick}>发布</button>
</div>
)
}
handclick = ()=>{
observer.dispatch("来自child2的问候")
}
}
export default class App extends Component {
render() {
return (
<div>
<Child1/>
<Child2/>
<Child3/>
</div>
)
}
}
react中状态树传参(context)
状态树传参是基于消费者生产这模式的
首先我们需要创建一个context对象作为基站把整个生产者和消费者包起来
const GlobalContext = React.createContext() //创建一个context对象
通过
<GlobalContext.Provider value={
{
sms:"短信服务",
call:"电话服务",
text:this.state.text,
changeState:this.changeState
}}>
<div>
<Child1/>
<Child2/>
<Child3/>
</div>
</GlobalContext.Provider>
每个子组件通过
<GlobalContext.Consumer>
{
context=>(
<div>
Child1----{
context.text}
</div>
)
}
</GlobalContext.Consumer>
这样就能直接访问到 父组件想传的状态
和外部的状态,入过需要修改父组件的状态的话,需要父组件创建一个函数 在子组件中调用
import React, {
Component } from 'react'
const GlobalContext = React.createContext() //创建一个context对象
class Child1 extends Component{
render() {
return (
<GlobalContext.Consumer>
{
context=>(
<div>
Child1----{
context.text}
</div>
)
}
</GlobalContext.Consumer>
)
}
}
class Child2 extends Component{
render() {
return (
<GlobalContext.Consumer>
{
context=>{
return <div>child2--{
context.call}
<button onClick={
()=>{
this.handclick(context)}}>child2通信</button>
</div>
}
}
</GlobalContext.Consumer>
)
}
handclick = (context)=>{
context.changeState("来自child2的问候")
}
}
export default class App extends Component {
state={
text:"私服"
}
changeState= (data)=>{
this.setState({
text:data
})
}
render() {
return (
<GlobalContext.Provider value={
{
sms:"短信服务",
call:"电话服务",
text:this.state.text,
changeState:this.changeState
}}>
<div>
<Child1/>
<Child2/>
</div>
</GlobalContext.Provider>
)
}
}
react的生命周期
首先我们需要知道
在16.2老的生命周期
16.2版本之后 -把之前的三个生命周期(因为作者说有些许bug都是一些边界问题)
-
componentWilMount
-
componentWillReceiveProps
-
componentWillUpdate
,换成了俩个新的生命周期
-
getDrivedStateFromProps
-
getSnapshotBeforeUpdate
初始化阶段
componentWillMount: render之前最后修改状态的一次机会
这个生命周期在ssr中 这个方法将会被多次调用, 所以会重复触发多
遍,同时在这里如果绑定事件, 将无法解绑,导致内存泄漏 , 变得不够安全高效逐步废
弃
render: 只能访问this.props和this.state,不允许修改状态和Dom输出
componentDidMount 成功render并渲染完成真实Dom后触发,可以修改Dom
- componentWillMount 和 componentDidMount 只执行一次而render执行多次只要有setState触发就会通过虚拟DOM,diff算法一系列操作执行render
更新阶段
componentWillReceiveProps 父组件修改属性触发
shouldComponentUpdate 返回false阻止render调用
- 如果你每次改变状态的话componentWillUpdate 和 componentDidUpdate 都会执行
所以这个这个生命周期会问你到底对比不对比如果你返回false的话就不对比了阻止render调用
shouldComponentUpdate(nextprops,nextstate){
console.log("shouldComponentUpdate",this.state.myname,nextstate.myname);
if(this.state.myname!==nextstate.myname){
return true
}
return false
}
需要注意这个生命周期自动接收两个参数nextstate就是修改之后的状态
componentWillUpdate 不能修改属性和状态 状态将要改变的时候
这个生命周期 更新前记录 DOM 状态, 可能会做一些处理,与componentDidUpdate相隔时间如果过长, 会导致 状态不可信。
比如就是当一个邮箱你在看一个邮箱的时候这个时候忽然多了些邮件滚动条会下沿,这个时候在没改变的时候我们需要记录下滚动条位置,以便下次邮件进来任然能找到你浏览的地方
但是由于和componentDidUpdate相隔时间如果过长, 会导致 状态不可信。
componentDidUpdate 可以修改DOM 更新完成之后
import React,{
Component} from 'react'
class Child extends Component{
componentWillReceiveProps(nextProps){
console.log("componentWillReceiveProps");
console.log("发送ajax数据",nextProps.myname)
}
componentDidMount(){
console.log("获取id发送ajax数据",this.props.myname)
}
render(){
return(
<div>
Child
</div>
)
}
}
export default class App extends Component{
state = {
myname:"123"
}
render(){
return (
<div>
{
this.state.myname}
<button onClick={
()=>{
this.setState({
myname:"456"
})
}}>click</button>
<Child myname={
this.state.myname}/>
</div>
)
}
}
注意这个生命周期也有一个自动接收一个形参数nextProps 改变了之后的属性
可以通过nextProps.myname访问到
销毁阶段
componentWillUnmount 在删除组件之前执行 常用于清除定时器或者清除事件的一些监听比如window.onScroll = null
新增的生命周期
getDerivedStateFromProps
这个生命周期代替了componentWillMount 和 gitcomponentReceiveProps 两个生命周期
注意他自动接收两个形参(nextprops,state)nextProps改变之后的状态 可以通过nextprops.XXX访问到
state是当前组件里面的状态 返回null 是不改变的意思(必须要return)
static getDerivedStateFromProps(nextProps,state){
document.title = nextProps.mytitle
// this.setState
// 处理初始状态
// return {
// myname:state.myname+1
// }
return null
}
import React, {
Component } from 'react'
class Title extends Component {
state = {
myname:"kerwin"
}
// componentWillMount() {
// document.title = this.props.mytitle
// }
// componentWillReceiveProps(nextProps){
// document.title = nextProps.mytitle
// }
// static getDerivedStateFromProps(nextProps,state){
// // console.log(state)
// // this.setState
// // 处理初始状态
// return {
// myname:state.myname.substring(0,1).toUpperCase()+state.myname.substring(1)
// }
// }
static getDerivedStateFromProps(nextProps,state){
document.title = nextProps.mytitle
// this.setState
// 处理初始状态
// return {
// myname:state.myname+1
// }
return null
}
render(){
return <div>{
this.state.myname}</div>
}
}
export default class App extends Component {
state ={
text:"1111"
}
render() {
return (
<div>
<ul>
<li onClick={
()=>this.handleClick("1111")}>11111</li>
<li onClick={
()=>this.handleClick("2222")}>222222</li>
<li onClick={
()=>this.handleClick("3333")}>333333</li>
</ul>
<Title mytitle={
this.state.text}/>
</div>
)
}
handleClick=(data)=>{
this.setState({
text:data
})
}
}
getDeribedStateFromProps异步
import React, {
Component } from 'react'
class List extends Component{
// componentWillMount() {
// console.log("发ajax",this.props.id)
// }
// componentWillReceiveProps(nextProps) {
// console.log("发ajax",nextProps.id)
// }
state = {
myid:""
}
static getDerivedStateFromProps(nextProps){
console.log("拿到这个最新的属性",nextProps.id)
// axios/
return {
myid:nextProps.id
}
}
render(){
return <div>
{
this.props.id}
</div>
}
componentDidUpdate(){
console.log("发ajax",this.state.myid)
}
}
export default class App extends Component {
state = {
id:0
}
render() {
return (
<div>
<ul>
<li onClick={
()=>{
this.setState({
id:0
})
}}>衣服</li>
<li onClick={
()=>{
this.setState({
id:1
})
}}>帽子</li>
<li onClick={
()=>{
this.setState({
id:2
})
}}>裤子</li>
</ul>
<List id={
this.state.id}></List>
</div>
)
}
}
getSnapshotBeforeUpdate
代替了之前的componentWillUpdate
它的执行时间在render之后,缩短了和componentDidMount的时间