React

父组件传过来的数据

属性

代码示例:

// src/test/Test04.jsx

import React, {Component} from 'react';
import Test05 from "./Test05";

export default class Test04 extends Component {
    render() {
        let myObj = {
            foo: 'foo',
            bar: 'bar'
        }
        let shiYu = '时雨'
        return (
            <div>
                <Test05 {...myObj} title={shiYu}/>
            </div>
        );
    }
}
// src/test/Test05.jsx

import React, {Component} from 'react';
import PropTypes from 'prop-types'

export default class Test05 extends Component {
    static ProTypes = {  // 定义类属性
        title: PropTypes.string.isRequired,  // 父类传过来的数据类型必须是string(isRequired:必须传的参数)
    }
    static defaultProps = {
        hello: 'Hello'  // 默认值
    }

    render() {
        console.log(this.props)
        let {hello, title, foo, bar} = this.props  // 解构
        return (
            <div>
                {hello + title + foo + bar}
            </div>
        );
    }
}

父子通信

  1. 用属性把父组件的状态给子组件使用
  2. 子组件使用回调函数通知父组件改变状态
  3. 父组件再用属性把状态传给子组件使用

代码示例:

// src/test/Test04.jsx

import React, {Component} from 'react';
import Test05 from './Test05'

export default class Test04 extends Component {
    state = {
        title: 'Foo'
    }

    render() {
        return (
            <div>
                {this.state.title}
                <Test05 title={(text) => {
                    this.setState({
                        title: text
                    })
                }}/>
            </div>
        );
    }
}
// src/test/Test05.jsx
import React, {Component} from 'react';

export default class Test05 extends Component {
    render() {
        return (
            <div>
                <button onClick={() => {
                    this.props.title('Bar')
                }}>改变父类状态
                </button>
            </div>
        );
    }
}
// src/test/Test04.jsx

import React, {Component} from 'react';

class Field extends Component {
    state = {
        value: ''
    }

    clear() {
        this.setState({
            value: ''
        })
    }

    render() {
        return (
            <div style={{background: 'gray'}}>
                <label>{this.props.label}</label>
                <input type={this.props.type} onChange={(evt) => {
                    this.setState({
                        value: evt.target.value
                    })
                }} value={this.state.value}/>
            </div>
        )
    }
}

export default class Test04 extends Component {
    name = React.createRef()
    pwd = React.createRef()

    render() {
        return (
            <div>
                <Field label={'用户名'} type={'text'} ref={this.name}/>
                <Field label={'密码'} type={'password'} ref={this.pwd}/>
                <button onClick={() => {  // 需要借助传过去的ref属性
                    console.log(this.name.current.state.value, this.pwd.current.state.value)  // 直接获取
                }}>提交
                </button>
                <button onClick={() => {
                    this.name.current.clear()  // 直接调用
                    this.pwd.current.clear()
                }}>清空
                </button>
            </div>
        );
    }
}

非父子通信

中间人模式

代码示例:

/* /src/css/css02.css */

.filmItem img {
    width: 100px;
    float: left;
}

.filmItem {
    overflow: hidden;
    padding: 10px;
}

.FilmDetail {
    position: fixed;
    right: 0;
    top: 100px;
    background: #30363d;
    width: 200px;
}
// src/test/Test04.jsx
// public/test.json

import React, {Component} from 'react';
import axios from "axios";
import '../css/css02.css'

class FilmItem extends Component {
    render() {
        let {name, poster, grade, synopsis} = this.props
        return (
            <div className={'filmItem'} onClick={() => {
                this.props.onEvent(synopsis)
            }}>
                <img src={poster} alt={name}/>
                <h4>{name}</h4>
                <div>评分:{grade}</div>
            </div>
        )
    }
}

class FilmDetail extends Component {
    render() {
        return (
            <div className={'FilmDetail'}>
                {this.props.value}
            </div>
        )
    }
}

export default class Test04 extends Component {
    constructor() {
        super()
        this.state = {
            list: [],
            value: ''
        }
        axios.get(`/test.json`).then((res) => {
            console.log(res.data.films)
            this.setState({
                list: res.data.films
            })
        }).catch((err) => {
            console.log(err)
        })
    }

    render() {
        return (
            <div>
                {
                    this.state.list.map((item) =>
                        <FilmItem key={item.filmId} {...item} onEvent={(value) => {
                            this.setState({
                                value: value
                            })
                        }}/>
                    )
                }
                <FilmDetail value={this.state.value}/>
            </div>
        );
    }
}

订阅发布模式

代码示例:

// src/test/Test04.jsx
// public/test.json

import React, {Component} from 'react';
import axios from "axios";
import '../css/css02.css'

let bus = {  // 调度中心
    list: [],
    subscribe(callback) {  // 订阅
        this.list.push(callback)
    },
    publish(text) {  // 发布
        this.list.forEach(callback => {
            callback && callback(text)  // 防止undefined
        })
    }
}

class FilmItem extends Component {
    render() {
        let {name, poster, grade, synopsis} = this.props
        return (
            <div className={'filmItem'} onClick={() => {
                bus.publish(synopsis)
            }}>
                <img src={poster} alt={name}/>
                <h4>{name}</h4>
                <div>评分:{grade}</div>
            </div>
        )
    }
}

class FilmDetail extends Component {
    constructor() {  // React实例化的时候会对其进行调用
        super()
        this.state = {
            text: ''
        }
        bus.subscribe((text) => {
            this.setState({
                text: text
            })
        })
    }

    render() {
        return (
            <div className={'FilmDetail'}>
                {this.state.text}
            </div>
        )
    }
}

export default class Test04 extends Component {
    constructor() {
        super()
        this.state = {
            list: [],
        }
        axios.get(`/test.json`).then((res) => {
            console.log(res.data.films)
            this.setState({
                list: res.data.films
            })
        }).catch((err) => {
            console.log(err)
        })
    }

    render() {
        return (
            <div>
                {
                    this.state.list.map((item) =>
                        <FilmItem key={item.filmId} {...item}/>
                    )
                }
                <FilmDetail/>
            </div>
        );
    }
}

context

代码示例:

// src/test/Test04.jsx
// public/test.json

import React, {Component} from 'react';
import axios from "axios";
import '../css/css02.css'

const GlobalContext = React.createContext()  // 创建context对象

class FilmItem extends Component {
    render() {
        let {name, poster, grade, synopsis} = this.props
        return (
            <GlobalContext.Consumer>
                {
                    (value) => {
                        console.log(value)
                        return (
                            <div className={'filmItem'} onClick={() => {
                                value.changeText(synopsis)
                            }}>
                                <img src={poster} alt={name}/>
                                <h4>{name}</h4>
                                <div>评分:{grade}</div>
                            </div>
                        )
                    }
                }
            </GlobalContext.Consumer>
        )
    }
}

class FilmDetail extends Component {
    render() {
        return (
            <GlobalContext.Consumer>
                {
                    (value) => {
                        return (
                            <div className={'FilmDetail'}>
                                {
                                    value.text
                                }
                            </div>
                        )
                    }
                }
            </GlobalContext.Consumer>
        )
    }
}

export default class Test04 extends Component {
    constructor() {
        super()
        this.state = {
            list: [],
            text: ''
        }
        axios.get(`/test.json`).then((res) => {
            console.log(res.data.films)
            this.setState({
                list: res.data.films
            })
        }).catch((err) => {
            console.log(err)
        })
    }

    render() {
        return (
            <GlobalContext.Provider value={{
                text: this.state.text,
                changeText: (value) => {
                    this.setState({  // 必须写成方法,否则render不会刷新
                        text: value
                    })
                }
            }}>
                <div>
                    {
                        this.state.list.map((item) =>
                            <FilmItem key={item.filmId} {...item}/>
                        )
                    }
                    <FilmDetail/>
                </div>
            </GlobalContext.Provider>
        );
    }
}

插槽

代码示例:

// src/test/Test04.jsx

import React, {Component} from 'react';

class Child extends Component {
    render() {
        return (
            <div>
                {this.props.children[0]}
                {this.props.children[1]}
                {this.props.children[2]}
            </div>
        )
    }
}

export default class Test04 extends Component {
    render() {
        return (
            <div>
                <Child>
                    <div>111</div>
                    <div>222</div>
                    <div>333</div>
                </Child>
            </div>
        );
    }
}