avatar

目录
React状态管理之局部状态管理

local state的管理

  1. 之前讨论的 redux、rematch、easy-peasy 都是全局的状态管理
  2. 对于大部分的简单业务,local state的管理并不麻烦,基本上就是控制一些弹窗的展示,loading的展示等


常见例子

  1. 例子中的逻辑是一个组件获取接口数据,并根据接口状态展示不同信息;
  2. 例子中是一个class组件,组件中既包含view视图,又包含model数据处理(状态存储和状态修改逻辑)
  3. 这样的写法优点是逻辑紧密关联,易于理解;缺点是逻辑难以复用
    javascript
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    import React from 'react';
    import axios from 'axios'

    class PageA extends React.Component {
    /**
    * loading 是否显示loading
    * data 数据
    * err 请求错误
    */
    state = {
    loading: false,
    data: null,
    err: null
    }

    async componentDidMount() {
    this.setState({ loading: true })
    try {
    const res = await axios.get('/api/pageA/options')
    this.setState({
    loading: false,
    data: res.data.data,
    })
    } catch (err) {
    this.setState({
    loading: false,
    error: err.message
    })
    }
    }

    render() {
    if (this.state.loading) {
    return <div>loading....</div>
    } else {
    return <div>{this.state.data}</div>
    }
    }
    }

    export default PageA;


class组件的逻辑复用:容器组件和视图组件分离

视图组件复用

  1. 容器组件只负责处理状态
  2. 视图组件之负责展示
  3. 一般UI组件库使用这种方式
    javascript
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    import React from 'react';
    import axios from 'axios'

    // 视图组件
    class Loading extends React.Component {
    render() {
    if (this.props.loading) {
    return <div>loading....</div>
    } else {
    return <div>{this.props.data}</div>
    }
    }
    }

    // 容器组件
    class PageA extends React.Component {
    /**
    * loading 是否显示loading
    * data 数据
    * err 请求错误
    */
    state = {
    loading: false,
    data: null,
    err: null
    }

    async componentDidMount() {
    this.setState({ loading: true })
    try {
    const res = await axios.get('/api/pageA/options')
    this.setState({
    loading: false,
    data: res.data.data,
    })
    } catch (err) {
    this.setState({
    loading: false,
    error: err.message
    })
    }
    }

    render() {
    return <Loading {...this.state}></Loading>
    }
    }

    export default PageA;

容器组件复用

  1. 高阶组件HOCTypescript的支持并不友好,代码可读性差
    javascript
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    import React from 'react';
    import axios from 'axios'

    // 视图组件
    class Loading extends React.Component {
    render() {
    if (this.props.loading) {
    return <div>loading....</div>
    } else {
    return <div>{this.props.data}</div>
    }
    }
    }

    // 容器组件
    function withLoading(Component) {
    return class PageA extends React.Component {
    /**
    * loading 是否显示loading
    * data 数据
    * err 请求错误
    */
    state = {
    loading: false,
    data: null,
    err: null
    }

    async componentDidMount() {
    this.setState({ loading: true })
    try {
    const res = await axios.get('/api/pageA/options')
    this.setState({
    loading: false,
    data: res.data.data,
    })
    } catch (err) {
    this.setState({
    loading: false,
    error: err.message
    })
    }
    }

    render() {
    return <Component {...this.state}></Component>
    }
    }
    }

    export default withLoading(Loading);
  2. renderProps会导致嵌套过多
    javascript
    1
    2
    3
    4
    5
    <WithLoading>
    {(props) => {
    <Loading {...props} />
    }}
    </WithLoading>


React Hook 实现逻辑复用

优势

  1. React Hook的一大特色就是状态逻辑复用
  2. 而且社区上已经积攒了很多的hook可以直接使用
    javascript
    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
    32
    33
    import React, { useState, useEffect } from 'react';
    import axios from 'axios'

    function useLoading() {
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);
    const [data, setData] = useState(null);

    useEffect(() => {
    setLoading(true);
    axios.get('/api/pageA/options').then(res => {
    setLoading(false);
    setData(res.data.data);
    }).catch(err => {
    setLoading(false);
    setError(err.message)
    })
    }, [])

    return [loading, error, data]
    }

    function PageA() {
    const [loading, error, data] = useLoading();

    if (loading) {
    return <div>loading....</div>
    } else {
    return <div>{data}</div>
    }
    }

    export default PageA;

不足

  1. 在function里组织业务代码,调用函数的时候需要注意函数声明的顺序
  2. 需要规范hook代码顺序
    javascript
    1
    2
    3
    4
    5
    6
    function APP(){
    // 1. useState, useRef
    // 2. 组件函数
    // 3. useEffect
    // 4. render逻辑
    }


文章作者: 盛顺炎
文章链接: https://www.shengshunyan.xyz/2020/04/15/React%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86%E4%B9%8B%E5%B1%80%E9%83%A8%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 果实的技术分享
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论