吴志勇的博客 吴志勇的博客
  • h5

    • HTML5&CSS3
  • scss

    • css预处理语言
  • JavaScript

    • JavaScript教程
    • Ajax
    • ES6教程
    • NodeJS
    • Typescript
  • 框架

    • Jquery
    • VUE
    • React
  • Swing专题
  • java基础
  • javaweb
  • 框架
  • 数据库
  • netty
  • 设计模式
  • 微服务及架构
  • 云原生
  • maven
  • 单元测试
工具
我的
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

吴志勇

......
  • h5

    • HTML5&CSS3
  • scss

    • css预处理语言
  • JavaScript

    • JavaScript教程
    • Ajax
    • ES6教程
    • NodeJS
    • Typescript
  • 框架

    • Jquery
    • VUE
    • React
  • Swing专题
  • java基础
  • javaweb
  • 框架
  • 数据库
  • netty
  • 设计模式
  • 微服务及架构
  • 云原生
  • maven
  • 单元测试
工具
我的
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • HTML5&CSS3

  • CSS预处理语言

  • JavaScript

  • nodejs

  • webpack

  • VUE

  • react

    • 01 【react入门】
    • 02 【面向组件编程】
    • 03 【事件处理】
    • 04 【生命周期】
    • 05 【条件渲染】
    • 06 【列表 & Key】
    • 07 【收集表单数据】
    • 08 【状态提升】
      • 1.介绍
      • 2.案例
    • 09 【组合组件】
    • 10 【初始化脚手架】
    • 11 【react-router 5】
    • 12 【react高级指引(上)】
    • 13【react高级指引(下)】
    • 14【react-Hook (上)】
    • 15【react-Hook (下)】
    • 16 【react-router 6】
    • 17【redux】
    • 18 【Redux Toolkit】
    • 19 【RTK Query】
    • 20 【react中使用ts】
    • 21 【styled-components的使用】
    • 22 【在react中使用Emotion】
    • 23 【UmiJS入门】
    • 24 【UmiJS基础】
  • Typescript
  • 前端
  • react
wuzhiyong
2024-09-22

08 【状态提升】

# 08 【状态提升】

# 1.介绍

所谓 状态提升 就是将各个子组件的 公共state 提升到它们的父组件进行统一存储、处理(这就是所谓的”单一数据源“),负责setState的函数传到下边的子级组件,然后再将父组件处理后的数据或函数props到各子组件中。

那么如果子组件 要 修改父组件的state该怎么办呢?我们的做法就是 将父组件中负责setState的函数,以props的形式传给子组件,然后子组件在需要改变state时调用即可。

实现方式

实现方式是 利用最近的共同的父级组件中,用props的方式传过去到两个子组件,props中传的是一个setState的方法,通过子组件触发props传过去的方法,进而调用父级组件的setState的方法,改变了父级组件的state,调用父级组件的render方法,进而同时改变了两个子级组件的render。

这是 两个有关连的同级组件的传值,因为react的单项数据流,所以不在两个组件中进行传值,而是提升到 最近的共同的父级组件中,改变父级的state,进而影响了两个子级组件的render。

官网介绍

通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。

# 2.案例

先写一个温度输入组件:

class TemperatureInput extends React.Component {
    state = {
        temperature: ''
    };
    handleChange = (e) => {
        this.setState({
            temperature : e.target.value
        })
    };
    render() {
        return (
            <fieldset>
                <legend>输入{scaleNames[this.props.scale]}:</legend>
                <input type="number" value={this.state.temperature} onChange={this.handleChange}
            </fieldset>
        )
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

这个组件就是一个普通的受控组件,有state和props以及处理函数。

我们在写另一个组件:

class Calculator extends React.Component {
    render () {
        return (
            <div>
                <TemperatureInput scale='c'/>
                <TemperatureInput scale='f'/>
            </div>
        )
    }
}
1
2
3
4
5
6
7
8
9
10

这个组件现在没有什么存在的价值,我们仅仅是给两个温度输入组件提供一个父组件,以便我们进行后续的状态提升。

现在我们看看网页的样子:

image-20221025123600431

我们可以输入摄氏度和华氏度,但是我们现在想要让这两个温度保持一致,就是我们如果输入摄氏度,那么下面的华氏度可以自动算出来,如果我们输入华氏度,那么摄氏度就可以自动算出来。

那么我们按照现在这种结构的话,是非常难以实现的,因为我们知道这两个组件之间没有任何关系,它们之间是不知道对方的存在,所以我们需要把它们的状态进行提升,提升到它们的父组件当中。

那我们看看如何做修改,首先把子组件(温度输入组件)的状态(state)全部删除,看看是什么样子:

    class TemperatureInput extends React.Component {

        handleChange = (e) => {

        };

        render() {
            return (
                <fieldset>
                    <legend>输入{scaleNames[this.props.scale]}:</legend>
                    <input type="number" value={this.props.temperature} onChange={this.handleChange}/>
                </fieldset>
            )
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

可以看到所有与state有关的东西全部删掉了,然后input的value也变成了props,通过父组件传入。那么现在这个温度输入组件其实就是一个受控组件了,仔细回忆一下我们之前讲的受控组件,看看是不是这样意思?

我们通常会在受控组件发生改变的时候传入一个onChange函数来改变受控组件的状态,那么我们这里也是一样,我们通过给 温度输入组件 传入某个函数来让 温度输入组件 中的input发生变化的时候调用,当然这个函数我们可以随意命名,假如我们这里叫做onTemperatureChange函数,那么我们继续修改子组件:

    class TemperatureInput extends React.Component {

        handleChange = (e) => {
            this.props.onTemperatureChange(e.target.value);
        };

        render() {
            return (
                <fieldset>
                    <legend>输入{scaleNames[this.props.scale]}:</legend>
                    <input type="number" value={this.props.temperature} onChange={this.handleChange}/>
                </fieldset>
            )
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

好了,我们的子组件差不多就是这样了,当然我们可以省略那个handleChange函数,因为可以看到这个函数就是调用了一下那个props里的函数,所以我们完全把input的onChange这么写 <input type="number" value={this.props.temperature} onChange={this.props.onTemperatureChange}/>这么写的话注意onTemperatrueChange函数的参数是那个事件,而不是我这里写的e.target.value。

再看看我们的父组件如何修改,我们首先补上state,以及子组件对应的onChange处理方法,以及子组件的值。写好之后大概是这个样子:

class Calculator extends React.Component {
    state = {
        celsius: '',
        fahrenheit: ''
    };

    onCelsiusChange = (value) => {
        this.setState({
            celsius: value,
            fahrenheit: tryConvert(value, toFahrenheit)
        });
    };

    onFahrenheitChange = (value) => {
        this.setState({
            celsius: tryConvert(value, toCelsius),
            fahrenheit: value
        });
    };

    render() {
        return (
            <div>
                <TemperatureInput scale='c' temperature={this.state.celsius}
                                  onTemperatureChange={this.onCelsiusChange}/>
                <TemperatureInput scale='f' temperature={this.state.fahrenheit}
                                  onTemperatureChange={this.onFahrenheitChange}/>
            </div>
        )
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

这里我们省略的摄氏度与华氏度的转换函数,比较简单,大家自行搜索方法。

上次更新: 2024-09-30 01:09:25

← 07 【收集表单数据】 09 【组合组件】→

Copyright © 2020-2025 wuzhiyong
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式