0

我有一个输入组件,它获取 url 作为输入并解析它(resolve=get 以某种方式预览该 url):

var resolver = require('resolver');
var UrlResolver = React.createClass({
    statics: {
        storeListeners: {
            onResolverStore: [ ResolverStore ]
        }
    },
    getInitialState: function() {
        return { value: '', resolves: [] };
    },
    onResolverStore: function(data) {
        var resolves = [].concat(this.state.resolves, data);
        this.setState({ resolves: resolves });
    },
    handleChange: function(event) {
        var value = event.target.value;
        this.setState({ value: value });
        this.executeAction(resolver, value);
    },
    render: function () {
        return (
            <input value={ this.state.value } onChange={ this.handleChange } />
            {
                this.state.resolves.map(function(data) {
                    return <ResolveView data={ data } />;
                });
            }
        );
    }
});

如您所见,UrlResolver 等待 ResolverStore 上的更改。当输入发生变化时,可能会发生这种变化。我的问题是当我有 10 个 UrlResolvers 时。在这种情况下,对一个输入的任何更改都会更改 ResolverStore,这将触发 10 个不同的事件,因此 10 个不同的 setStates 将导致 10 次重新渲染。所有这一切,而只有一个输入应处理此更改。这样 9 个组件也会添加一个不属于它们的解析数据。

这种需求的解决方案是什么?

4

1 回答 1

0

您似乎正在使用将数据从存储推送到组件的 Flux 实现,该实现获取存储正在包装的所有状态并将其推送到组件状态。当不同的组件只对该数据的一个子集感兴趣,或者如果需要首先查询数据时,这就会成为一个问题。

我对 Flux 的看法是,数据应该由商店中的组件提取,而不是相反。这样,您就可以在组件中获得您感兴趣的数据的完全灵活性,而不会丢失单向数据流。

一个例子是这样的:

var MyComponent = React.createClass({
  getInitialState() {
    return {
      items: []
    };
  },
  componentWillMount() {
    MyStore.on('change', this.loadItems);
    this.loadItems();
  },
  componentWillUnmount() {
    MyStore.off('change', this.loadItems);
  },
  loadItems() {
    MyStore.find(/* search params or find by id goes here */)
      .then(items => this.setState({items: items}));
  },
  render() {
    return (
      <ul>
        {this.state.items.map(item => <li>{item}</li>)}
      </ul>
      <button onClick={e => MyActions.add()}>Add new stuff</button>
    );
  }
});

如您所见,由组件来查询商店以获取组件感兴趣的任何数据,但组件仍然订阅对商店中状态的任何更改。在此示例中,它是一个项目数组,但它也可以是通过 id 获取的单个项目,并作为道具传递给组件。

如果您在内存中拥有所有状态,则推送存储的整个状态效果很好,但对于由 REST API 或 WebSQL/IndexedDB 数据库支持的存储,我发现此模型更简单。

编辑

为了进一步阐明为什么我更喜欢从商店拉取而不是推送到组件。通过让组件只获取它需要的数据而不是让商店将它的整个状态推送给你,可以更容易地查看它是否值得重新渲染。

在我的示例中,它会在调用loadItems操作后立即调用每个组件实例,但是通过从存储中提取,您可以通过检查组件感兴趣的数据是否已更改来让组件短路。这可以通过让您的商店使用不可变数据来完成,这意味着您可以使用引用相等来确定某些内容是否已更改。另一种选择是传递更改事件中实际更改的内容。然后组件可以检查更改项的 id 是否是它关心的东西,如果不是,则跳过重新渲染。

不过,我建议不要进行此类检查,因为它很容易陷入组件的陷阱,几乎不知道它是否应该重新渲染。如果您改为从您的商店返回不可变的列表/记录/地图,这只是对返回的内容与之前必须知道的组件感兴趣的内容是否已更改的内容进行相等性检查。

于 2015-04-17T05:47:58.013 回答