在父状态更改时强制子组件更新

时间:2018-01-22 18:17:21

标签: javascript reactjs react-redux

我有一个MyList组件可以获取项目,允许过滤和排序。此组件已在应用程序的其他部分中使用,并且运行良好。它使用渲染道具来渲染项目,使其接受类型函数的renderItem道具。

现在我正在构建一个简单的列表,允许使用上述组件选择项目,并且我正在检查渲染道具renderItem方法中的选定状态。问题是,当我更改MySelectableList的状态时,MyList组件不会更新,因为它的props不会更改(它始终是相同的绑定函数renderProp)。现在我强迫用this.renderItem = this.renderItem.bind(this);渲染孩子,但我不喜欢它,我知道我可以用ref更新子组件,但我也不喜欢它。

当父状态更改时,是否有更好的方法强制子组件呈现?我做错了吗?

MySelectableList的完整代码:

class MySelectableList extend Component {
    constructor (props) {
        super(props);

        this.state = {
            selectedItems: [],
        };
        this.renderItem = this.renderItem.bind(this);
        this.toggle = this.toggle.bind(this);
        this.isSelected = this.isSelected.bind(this);
    }

    toggle (item) {
        const newItems = this.state.selectedItems.slice(0);
        const index = newItems.indexOf(item.uuid);
        if (index === -1) {
            newItems.push(item.uuid);
        } else {
            newItems.splice(index, 1);
        }
        this.setState({ selectedItems: newItems });
        // Force MyList to re-render by tricking react that it's different
        this.renderItem = this.renderItem.bind(this);
    }

    isSelected (item) {
        return this.state.selectedItems.includes(item.uuid);
    }

    renderItem (item) {
        return (<MySelectableItem
            key={ item.uuid }
            item={ item }
            toggle={ this.toggle }
            selected={ this.isSelected(item) } />);
    }

    render () {
        return (
            <div>
                ...
                <MyList renderItem={ this.renderItem } />
                ...
            </div>
        );
    }
}

提前致谢。

修改

MyList组件使用connect连接到redux商店。我发现connectMyList组件缺失渲染的原因,只使用“vanilla”反应组件才能正常工作。

我在此代码框中重现了该问题:https://codesandbox.io/s/0mov14nmmp

2 个答案:

答案 0 :(得分:1)

因为您询问了如何以更友好的方式做到这一点

更好的方法是:

render () {
        return (
            <div>
                <MyList {...whateeverExtraPropsyouWantToPass}>
                   <MySelectableItem
                       key={ item.uuid }
                       item={ item }
                       toggle={ this.toggle }
                       selected={ this.isSelected(item) } />
                </MyList>
            </div>
        );

然后你的MyList看起来像这样:

render () {
        return (
            <div>
               ...//your other MyList code
               ...
               {this.props.children}
            </div>
        );

这看起来更易读,更易于维护且易于调试。但我相信这对你来说显而易见。因为,你问过a react friendly way,这是你能做的最友善的反应方式。

我不会建议不必要的,显式尝试渲染任何组件。直到并且除非它是唯一的方式,但在您的组件中并非如此。

答案 1 :(得分:0)

实现MyList的方式没有任何问题。 React Native FlatList具有相同的模式。但是为什么你也不把项目作为属性传递给MyList,所以它就像

<MyList items={this.state. selectedItems} renderItem={this.renderItem} />

这样MyList将重新渲染,因为items属性发生了变化。还需要items属性,因为我假设在你的MyList组件中你需要做items.map函数吗?否则你怎么知道你需要渲染多少项呢?