【问题标题】:State management in ReactJSReactJS 中的状态管理
【发布时间】:2018-03-31 02:51:08
【问题描述】:

我正在构建一个与地图相关的组件,其中centerzoomfeatures 等属性将由props 推送到组件。挂载地图组件后,我会根据props设置地图视图并添加一些功能。

当状态发生变化时,我不确定通过componentWillReceiveProps 更新地图视图是否正确。

另外,当用户与地图交互时,地图视图会发生变化,这意味着地图组件的内部状态发生了变化,是否需要通过setState更新状态以保持状态一致性?

【问题讨论】:

  • And when the state changed I am not sure if updating the map view by componentWillReceiveProps,谁在改变状态?地图组件本身还是其他?

标签: reactjs state-management


【解决方案1】:

为了详细说明前面的答案,混合本地状态和全局状态的技巧是:

  • 尽可能保持本地化:任何给定状态项的范围越小,它给您带来的错误就越少。
  • 必要时将状态传递给父级(状态提升)
  • 准备好让父级传递影响您存储的本地状态的新状态。

这是一个演示如何完成此操作的示例。我刚刚从create-react-app 获取了一个入门应用程序,并添加了一个带有缩放属性的“地图”组件作为示例。

App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import Map from './Map';

import './App.css';

class App extends Component {
    constructor(props) {
        super(props);
        this.state = {zoom: 1.0}
        this.handleZoomChange = this.handleZoomChange.bind(this);
    }

    handleZoomChange(zoom) {
        this.setState( {zoom: zoom} );
    }

    render() {
        return (
            <div className="App">
                <header className="App-header">
                    <img src={logo} className="App-logo" alt="logo" />
                    <h1 className="App-title">Welcome to React</h1>
                </header>
                <p className="App-intro">
                    <Map zoom={this.state.zoom} onZoomChange={this.handleZoomChange}/>
                </p>
            </div>
       );
    }
}

export default App;

Map.js

import React, { Component } from 'react';

class Map extends Component {

    constructor(props) {
        super(props);
        this.state = {zoom: this.props.zoom}

        this.handleSubmit = this.handleSubmit.bind(this);
        this.handleChange = this.handleChange.bind(this);
    }

    // Called when the parent wants us to re-render with
    // new props. Note that the new props may be the same
    // as the old ones.
    componentWillReceiveProps(nextProps) {
        if( nextProps.zoom ) {
            this.setState( {zoom: nextProps.zoom } );
        }
    }

    // User submits the form. Pass it up to our parent.
    handleSubmit(e) {
        e.preventDefault();
        this.props.onZoomChange(this.state.zoom);
    }

    // Control the input field
    handleChange(e) {
        this.setState( {zoom: e.target.value} );
    }

    render() {
        return (
            <form onSubmit={this.handleSubmit}>
                <input type="text" value={this.state.zoom} onChange={this.handleChange}/>
                <button type="submit">Save</button>
            </form>
        );
    }

};

export default Map;

因此您可以在此处看到缩放状态保持在地图组件中,直到用户按下保存按钮。此时,它被提升到父级(App 组件),父级将其保存在自己的状态中。然后调用 componentWillReceiveProps() 以准备重新渲染 Map 组件,并且 Map 组件再次更新其状态(在这种情况下为相同的值,但在其他情况下可能不会)。

【讨论】:

    【解决方案2】:
    1. 对于initial rendering and initialisation,可以将props从父组件传递到地图组件。

      例如初始缩放、地理围栏、默认标记等。

    2. 现在从这里开始,如果地图组件有任何变化,比如新标记、地理围栏,那么你应该manage local state at Map Component level and store the state internally with state。万一,APP需要一些关于这个更改数据的信息,然后state lifting

    3. 从APP中,如果地图组件再次发生更改,例如重置地图组件,您应该使用componentWillReceiveProps检索道具并使用setState使用这些新的重置数据再次渲染地图组件。现在,这些新传递的道具将保存在组件状态。

    【讨论】:

    • 对于您的建议2:这是否意味着除非您需要组件外部可以解除状态的状态,否则无需在组件和APP之间保持状态一致?如果是,如何使用诸如reduxmobx 之类的商店库来解除所需的状态?
    • 假设你把标记.now,locationchange事件将触发。在这里你可以更新组件状态并将状态提升给父母
    猜你喜欢
    • 2015-01-22
    • 2021-05-17
    • 1970-01-01
    • 2020-04-12
    • 2020-04-20
    • 2022-07-28
    • 1970-01-01
    • 2019-11-28
    • 2020-05-10
    相关资源
    最近更新 更多