React学习笔记21-非父子通信(状态提升)

发布时间 2023-11-08 10:14:12作者: SadicZhou

1.状态提升(中间人模式)的定义

React中的状态提升概括来说,就是将多个组件需要共享的状态提升到它们最近的父组件
上.在父组件上改变这个状态然后通过props分发给子组件。

2.状态提升的使用

简单讲解一下下面的代码,下面模拟了一个电影列表和详情页面。

进行通信的是列表的item和详情组件。

可以看到先在父组件APP中进行ajax请求拿到所有的列表item数据,然后通过父传子传给item,

同时传递一个getDetail函数给item组件作为它点击事件的回调。这个方法接受了一个存放详情信息的形参。

然后在父组件定义一个State detail 用来传递给详情组件作为它的属性来渲染详情信息。

getDetail方法会用接受的行参数来进行setState改变detail,这时就会重新执行render。

详情信息就从item传递到了详情。实现了兄弟组件的通信。

可以看到在中间人模式下,兄弟组件的所有属性都是由父组件来分发的。并且都能通过父组件的setState来控制。

所以说本质上中间人模式也就是父子通信的应用。

import React, { Component } from 'react'
import axios from 'axios'
export default class App extends Component {
    constructor() {
        super()
        this.state = {
            filmList: [],
            detail: ""
        }

    }
    componentDidMount() {
        axios.get('http://localhost:3000/filmlist.json').then(res => {
            console.log(res.data.data.films)
            this.setState({
                filmList: res.data.data.films
            })
        })
    }
    render() {
        return (
            <div>
                {this.state.filmList.map(item => {
                    return (
                        <FilmItem getFilmDetail={
                            (detail) => {
                                /* 
                                父组件接收到之后,执行this.getFilmDetail(detail)
                                更新状态,然后分发给FilmDetail组件,
                                通过父组件为中间人模式实现兄弟传参
                                */
                                this.getFilmDetail(detail)
                            }
                        } {...item} key={item.filmId}></FilmItem>
                    )
                })}
                <FilmDetail detail={this.state.detail} ></FilmDetail>
            </div>
        )
    }
    getFilmDetail(detail) {
        console.log(detail)
        this.setState({
            detail: detail
        })
    }
}
/* 受控组件 */
class FilmItem extends Component {
    render() {
        console.log(this.props);
        return (
            <div style={{ overflow: 'hidden', padding: '10px' }} onClick={
                () => {
                    /* 
                    先将detail通过回调函数传给父组件
                    */
                    console.log(this.props.synopsis)
                    this.props.getFilmDetail(this.props.synopsis)
                }
            }>
                <img style={{ width: '100px', float: "left" }} src={this.props.poster} alt="" />
                <h4>{this.props.name}</h4>
                <h5>观众评分:{this.props.grade}</h5>

            </div>
        )
    }
}

class FilmDetail extends Component {
    render() {
        return (
            <div style={{ position: 'fixed', right: '0', top: '100px', background: 'yellow', width: "200px", padding: "10px" }}
            >{this.props.detail}</div>
        )
    }
}