【问题标题】:React best-practices -- pure or non-pure components? fetching data in componentWillMount?React 最佳实践——纯组件还是非纯组件?在 componentWillMount 中获取数据?
【发布时间】:2015-04-21 11:24:03
【问题描述】:

我在 Meteor 中使用 React。似乎有两种处理方式......

以流星排行榜为例,我们有一个呈现姓名和分数的玩家列表。

纯粹的做事方式是获取所有玩家并传递到 playerList 组件中,然后将其划分为 playerItem 组件。一切都是用道具完成的,这些模板是纯粹的。每当玩家更改时,我们可以使用 Meteor 的响应性来使用 React 重新渲染所有内容

Tracker.autorun =>
  players = Players.find().fetch()
  React.render(React.createElement(PlayersList, {players:players}), document.body)

(传递给自动运行的函数将在玩家更改时重新运行)

这几乎正是 Pete Hunt 在他的 Meteor-React presentation demo 中所做的。

现在另一种方法似乎更有效和细粒度,但不是纯粹的。即向 PlayersList 组件传递一个 playerId 列表。向 PlayerItem 组件传递一个 playerId 并让 PlayerItem 获取特定的玩家并根据组件的状态呈现玩家的姓名和得分。

// inside the PlayerItem component
componentWillMount: =>
  Tracker.autorun =>
    this.setState('player', Players.findOne(this.props.playerId))

现在 PlayerItem 不是纯粹的。每当玩家的分数发生变化时,只会重新渲染代表该玩家的 PlayerItem。如果我们确保只向 PlayersList 传递一个 playerId 列表,那么只会在添加或删除玩家时重新渲染 PlayersList 组件。

Tracker.autorun =>
  playerIds = _.pluck('_id',Players.find({}, {fields:{_id:1}}).fetch())
  React.render(React.createElement(PlayersList, {playerIds: playerIds}), document.body)

这是有道理的,因为现在我们对 React 的渲染周期进行了细粒度的控制,并且我们不会在任何事情发生变化时对每个玩家的整个状态进行轰炸反应。然而,这似乎不符合 React 的设计精神。现在我们到处都有内部状态,我们的组件不是纯的!

在我的印象中,React 希望我做事的方式是使用全局状态和纯组件,并且仅依赖于 React 的协调超级快速和高效这一事实。这只是让我有点不舒服,因为非纯方法似乎更有效。

无论如何,我刚开始使用 React,所以虽然我阅读了所有文档,但我不确定我知道我在说什么。所以我想知道——我什么时候应该坚持使用纯组件,什么时候可以使用非纯组件?我应该在组件中获取数据还是应该严格地将 react 视为渲染引擎?

【问题讨论】:

    标签: javascript meteor reactjs


    【解决方案1】:

    React.render 与在顶级组件中执行它之间几乎没有区别。无论哪种方式,它都会更新状态或道具、渲染和区分新旧虚拟 dom。

    我会让 PlayerList 获取所有玩家,然后将它们传递给 PlayerItem 组件。您应该在componentDidMount 中绑定到外部api,并确保在componentWillUnmount 中取消绑定。 componentWillMount 函数的作用类似于构造函数:设置任何非状态实例属性。

    PlayerItem 应该实现 shouldComponentUpdate 以提高性能。您可以在空闲时间执行此操作,因为它是一种不会影响其余代码的优化。

    作为旁注,您可以实现一个有助于流星绑定的 mixin。

    var MeteorMixin = {
        getInitialState: function(){
            return this.getUpdatedState();
        },
        componentDidMount: function(){
            this._meteorMixinComputation = Tracker.autorun(function(){
                this.setState(this.getUpdatedState());
            }.bind(this));
        },
        componentWillUnmount: function(){
            this._meteorMixinComputation.stop();
        }
    };
    

    然后您的组件将如下所示:

    mixins: [MeteorMixin],
    getUpdatedState: -> {players: Players.find({}).fetch()}
    render: ->
       ...
    

    免责声明:我不使用流星,所以这可能是一个问题。

    【讨论】:

    • This Mixin accomplishes all that。所以只是为了澄清,你是说我应该使用处理状态的顶级组件而不是全局自动运行。然后我可以用流星的反应性做任何我想要的 this.setState 更新。但是只有顶级组件应该有状态。 PlayersList 和 PlayerItem 应该都是纯的吧?
    • 是的,完全正确。并感谢编辑 user3374348 :-)
    猜你喜欢
    • 2020-12-09
    • 1970-01-01
    • 2011-05-17
    • 2019-02-07
    • 2019-10-10
    • 1970-01-01
    • 2016-06-05
    • 2020-06-01
    • 1970-01-01
    相关资源
    最近更新 更多