ReactJS状态与道具

nic*_*las 120 reactjs

这可能是在回答问题和固执己见之间的那条线,但我会来回顾如何构建ReactJS组件,因为复杂性增加并且可以使用某些方向.

来自AngularJS,我希望将我的模型作为属性传递给组件,并让组件直接修改模型.或者我应该将模型拆分为各种state属性,并在向上游发送时将其重新编译回来?什么是ReactJS方式?

以博客文章编辑器为例.试图直接修改模型最终看起来像:

var PostEditor = React.createClass({
  updateText: function(e) {
    var text = e.target.value;
    this.props.post.text = text;
    this.forceUpdate();
  },
  render: function() {
    return (
      <input value={this.props.post.text} onChange={this.updateText}/>
      <button onClick={this.props.post.save}/>Save</button>
    );
  }
});
Run Code Online (Sandbox Code Playgroud)

这似乎不对.

是否更多是React方法来创建我们的text模型属性state,并在保存之前将其编译回模型:

var PostEditor = React.createClass({
  getInitialState: function() {
    return {
      text: ""
    };
  },
  componentWillMount: function() {
    this.setState({
      text: this.props.post.text
    });
  },
  updateText: function(e) {
    this.setState({
      text: e.target.value
    });
  },
  savePost: function() {
    this.props.post.text = this.state.text;
    this.props.post.save();
  },
  render: function() {
    return (
      <input value={this.state.text} onChange={this.updateText}/>
      <button onClick={this.savePost}/>Save</button>
    );
  }
});
Run Code Online (Sandbox Code Playgroud)

这不需要调用this.forceUpdate(),但随着模型的增长,(帖子可能有作者,主题,标签,评论,评级等......)组件开始变得非常复杂.

是第一种使用ReactLink的方法吗?

mrv*_*vol 97

更新2016: React已更改,解释"props vs state"变得非常简单.如果组件需要更改数据 - 将其置于某个状态,否则将置于道具中.因为道具现在是只读的.

道具和国家之间的确切区别是什么?

你可以在这里找到很好的解释(完整版)

改变道具和状态

  • 不推荐使用`setProps`,不应该使用它.替换是重新渲染组件并让React处理差异. (2认同)

jxg*_*jxg 64

你的第二种方法更像是它.React并不关心模型,因为它关心的是价值以及它们如何在您的应用中流动.理想情况下,您的帖子模型将存储在根目录中的单个组件中.然后创建子组件,每个组件都使用模型的一部分.

您可以将回调传递给需要修改数据的子项,并从子组件中调用它们.

直接修改this.props或this.state不是一个好主意,因为React将无法接收更改.那是因为React对你的后道具进行浅层比较,以确定它是否已经改变.

我做了这个jsfiddle来展示数据如何从外部组件流向内部组件:

http://jsfiddle.net/jxg/M3CLB/

handleClick方法显示了3种(im)正确更新状态的方法:

var Outer = React.createClass({

  getInitialState: function() {
    return {data: {value: 'at first, it works'}};
  },

  handleClick: function () {

    // 1. This doesn't work, render is not triggered.
    // Never set state directly because the updated values
    // can still be read, which can lead to unexpected behavior.

    this.state.data.value = 'but React will never know!';

    // 2. This works, because we use setState

    var newData = {value: 'it works 2'};
    this.setState({data: newData});

    // 3. Alternatively you can use React's immutability helpers
    // to update more complex models.
    // Read more: http://facebook.github.io/react/docs/update.html

    var newState = React.addons.update(this.state, {
      data: {value: {$set: 'it works'}}
    });
    this.setState(newState);
 },

  render: function() {
      return <Inner data={this.state.data} handleClick={this.handleClick} />;
  }
});
Run Code Online (Sandbox Code Playgroud)

  • 是的,你可以调用`forceUpdate`,但此时你正在“泄漏”React。将 `setState()` 回调传递给不透明模型可能会更好,以避免必须手动触发重新渲染。 (2认同)

Fiz*_*han 35

来自React doc

props是不可变的:它们从父级传递,并由父级"拥有".为了实现交互,我们向组件引入了可变状态.this.state是组件的私有,可以通过调用this.setState()来更改.更新状态后,组件将重新呈现自身.

TrySpace:当更新props(或state)时(通过setProps/setState或parent),组件也会重新渲染.


onm*_*133 16

阅读" 反思中的思考":

让我们通过每一个,找出哪个是州.只需询问有关每个数据的三个问题:

  1. 它是通过道具从父母那里传来的吗?如果是这样,它可能不是状态.
  2. 它会随着时间而改变吗?如果没有,它可能不是状态.

  3. 您可以根据组件中的任何其他状态或道具来计算它吗?如果是这样,那就不是状态.


Jim*_*ien 13

我不确定我是否回答了你的问题,但我发现,特别是在大型/不断发展的应用程序中,容器/组件模式运行得非常好.

基本上你有两个React组件:

  • 一个"纯"的显示组件,处理样式和DOM交互;
  • 容器组件,用于访问/保存外部数据,管理状态和呈现显示组件.

注意这个例子可能过于简单,无法说明这种模式的好处,因为对于这种简单的案例来说,它非常冗长.

/**
 * Container Component
 *
 *  - Manages component state
 *  - Does plumbing of data fetching/saving
 */

var PostEditorContainer = React.createClass({
  getInitialState: function() {
    return {
      text: ""
    };
  },

  componentWillMount: function() {
    this.setState({
      text: getPostText()
    });
  },

  updateText: function(text) {
    this.setState({
      text: text
    });
  },

  savePost: function() {
    savePostText(this.state.text);
  },

  render: function() {
    return (
      <PostEditor
        text={this.state.text}
        onChange={this.updateText.bind(this)}
        onSave={this.savePost.bind(this)}
      />
    );
  }
});


/**
 * Pure Display Component
 *
 *  - Calculates styling based on passed properties
 *  - Often just a render method
 *  - Uses methods passed in from container to announce changes
 */

var PostEditor = React.createClass({
  render: function() {
    return (
      <div>
        <input type="text" value={this.props.text} onChange={this.props.onChange} />
        <button type="button" onClick={this.props.onSave} />
      </div>
    );
  }
});
Run Code Online (Sandbox Code Playgroud)

优点

通过将显示逻辑和数据/状态管理分开,您有一个可重复使用的显示组件:

  • 可以使用react-component-playground之类的东西轻松地使用不同的道具集进行迭代
  • 可以使用不同的容器包装以实现不同的行为(或与其他组件组合以构建应用程序的更大部分

您还有一个处理所有外部通信的容器组件.如果您稍后对*进行任何重大更改,这将使您更容易灵活地访问数据.

这种模式也使编写和实现单元测试变得更加直接.

迭代了几次大型React应用程序,我发现这种模式可以让事情变得相对轻松,特别是当你有更大的组件具有计算样式或复杂的DOM交互时.

*阅读通量模式,看看Marty.js,这很大程度上激发了这个答案(我最近一直在使用很多) Redux(和react-redux),它非常好地实现了这种模式.

请注意2018年或之后阅读此内容的人:

自从这个答案写完以来,React已经发展了很多,尤其是在引入Hooks之后.但是,此示例中的基础状态管理逻辑保持不变,更重要的是,保持状态和表示逻辑分离所带来的好处仍然以相同的方式应用.