响应依赖于州

时间:2017-10-02 07:46:38

标签: reactjs

我们目前正在重构使用更高阶的组件。在大多数情况下,这使一切变得更加简单。

我们有HOC用于获取数据和收听商店。例如,我们有connectStores,它包含要订阅的商店列表和获取数据的函数(作为额外的道具传递):

connectStores(FooComponent, [FooStore], function (props) {
    return {
        foo: FooStore.get(props.id),
    };
});

但是,有一些地方从商店获取数据的过程取决于状态。例如,我们有一个SelectFooPopup,它向用户显示可供选择的项目列表。但是还有一个搜索框来过滤列表,所以目前组件直接监听商店,然后像这样获取数据本身:

componentDidMount() {
    var self = this;
    this.listenTo(FooStore, 'change', function () {
        self.forceUpdate();
    });
}

render() {
    var items = FooStore.search(this.state.searchText);
    // render...
}

this.listenTo是我们试图用HOC代替的mixin,所以我们可以使用ES6类)

我可以想到几个选项,但我不喜欢它们中的任何一个:

选项1:删除listenTo并手动清除侦听器

componentDidMount() {
    var self = this;
    this.listener = function () {
        self.forceUpdate();
    };

    FooStore.on('change', this.listener);
}

componentWillUnmount() {
    if (this.listener) {
        FooStore.removeListener('change', this.listener);
    }
}

render() {
    var items = FooStore.search(this.state.searchText);
    // render...
}

我真的很讨厌必须手动执行此操作。我们在使用listenTo mixin之前就这样做了,而且很容易出错。

当订阅必须直接从服务器获取数据而不是使用预先填充的商店时,这也无济于事。

选项2:使用connectStores但不返回任何额外数据

class SelectFooPopup extends React.Component {
    render() {
        var items = FooStore.search(this.state.searchText);
    }
}

connectStores(SelectFooPopup, [FooStore], function (props) {
    // Just to forceUpdate
    return {};
});

这对我来说感觉不对。当我们开始优化纯组件并且突然子组件不再重新渲染时,这就会出问题。

选项3:使用connectStores获取所有数据,然后在渲染中过滤

class SelectFooPopup extends React.Component {
    render() {
        var items = filterSearch(this.props.items, this.state.searchText);
    }
}

connectStores(SelectFooPopup, [FooStore], function (props) {
    return {
        items: FooStore.getAllItems(),
    };
});

但是现在我必须有一个完全独立的filterSearch函数。这不应该是商店的方法吗?

此外,它在这个例子中没有太大的区别,但我有其他组件有类似的问题 他们从服务器获取数据,而不是订阅预先填充的商店。在这些情况下 数据集太大而无法全部发送并在以后过滤,因此在获取数据时,searchText必须可用。

选项4:创建父组件以保持状态

有时这是正确的解决方案。但它感觉不对劲。 searchText是 this 组件状态的一部分。它属于呈现搜索框的相同位置。

将它移到一个单独的组件是令人困惑和人为的。

选项5:使用“parentState”HOC

function parentState(Component, getInitialState) {
    class ParentStateContainer extends React.Component {
        constructor(props) {
            super();
            this.setParentState = this.setParentState.bind(this);
            if (getInitialState) {
                this.state = getInitialState(props);
            } else {
                this.state = {};
            }
        }

        setParentState(newState) {
            this.setState(newState);
        }

        render() {
            return <Component {...this.props} {...this.state} setParentState={ this.setParentState } />;
        }
    }
    return ParentStateContainer;
}

// Usage:
parentState(SelectFooPopup, function (props) {
    return {
        searchText: '',
    };
});

// In handleSearchText:
this.props.setParentState({ searchText: newValue });

这也感觉非常错误,我应该把它扔掉。

结论

在React中,我们有两个级别:propsstate

在我看来,实际上有4个级别要考虑:

  1. 道具
  2. 仅依赖道具的数据
  3. 状态
  4. 取决于道具和州的数据
  5. 呈现
  6. 我们可以使用HOC实现第2层。但是我们如何实现第4层?

0 个答案:

没有答案