强制React容器刷新数据

时间:2017-04-24 13:41:42

标签: reactjs

在我的React应用程序中,我有两种不同类型的组件: presentation containers 。它大致在Dan Abromov的"Presentational and Container Components"之后,除了我不使用Flux或Redux。

现在,我有以下结构:

UsersContainer
├── UsersListContainer
|   └── UsersListView
└── AddUserContainer

UsersListContainer负责从某些REST API加载数据,如果成功,则委托将该数据呈现给UsersListView

AddUserContainer再次通过调用REST API负责添加新用户。现在,当成功时,我希望UsersListContainer刷新其数据。

我能想到的最好的是:

class AddUserContainer extends React.Component {
  render() {
    // Other UI elements omitted for brevity
    return (<button onClick={ e => props.onUserAdded() }>Add user</button>);
  }
}

class UsersListContainer extends React.Component {
  componentWillMount() {
    // start fetching data using window.fetch;
    // the promise callback will but retrieved data into this.state
  }
  render() {
    return (<table></table>);
  }
}

class UsersContainer extends React.Component {
  render() {
    const forceUpdate = this.setState({ ...this.state, refreshToken: Math.random() });
    // Other UI elements omitted for brevity
    <UsersListContainer key={ this.state.refreshToken } />
    <AddUserContainer onUserAdded={ forceUpdate } />
  }
}

但这种方法感觉错误地使用了key道具。是否有更好/更优雅的方式来做到这一点?

2 个答案:

答案 0 :(得分:4)

查看react-refetch,它为fetch提供了一个很好的API,并允许您实现演示和容器组件模式,而无需使用Flux / Redux进行API调用。

它还允许您处理加载和错误状态,这对于当今体面的Web应用程序来说肯定是必需的。

在下面的示例中,我摆脱了UsersListContainer,但也将AddUserContainer移到UsersContainer。这使您的UsersListView成为UsersContainer的演示组件。随意更改命名,如您所愿。这样我就可以将refreshUsers道具传递给AddUserContainer

// UsersContainer.js

const Container = ({ usersFetch, refreshUsers }) => {
    if (userFetch.pending) {
        return <LoadingDisplay />
    } else if (usersFetch.rejected) {
        return <ErrorDisplay error={ usersFetch.reason } />
    } else if (usersFetch.fulfilled) {
        return (
            <UsersListView users={ usersFetch.value } />
            <AddUserContainer handleAddUser={ refreshUsers } />
        );
    }
};

const refetch = (props) => {
    const usersFetch = `/api/users`;

    return {
        usersFetch: usersFetch,
        refreshUsers: () => ({
            usersFetch: { ...usersFetch, force: true, refreshing: true }
        }),
    };
};

export default connect(refetch)(Container);

查看文档以获取更多示例。我个人更喜欢对API密集型应用程序使用react-refetch,而不是在Redux中实现调用。

答案 1 :(得分:1)

如果您还不想使用Flux或Redux,那么在我看来,更新对等组件(在您的情况下,UsersListContainer和AddUserContainer)对React来说是反模式的。

对我而言,React的主要思想是将道具从父母传递给孩子,因此,Irvin Lim的想法是摆脱了UsersListContainer,但将AddUserContainer移到了UsersContainer&#34;将使您更容易控制何时更新组件!

您当前的接近和我的想法是相同的:在您的 UsersContainer 中,创建一个强制更新它的方法,然后将其传递给 AddUserContainer ,并在添加此AddUserContainer之后用户,您在父级上触发该更新方法:

<AddUserContainer onUserAdded={ this.props.updatingParent } />

供您参考,或者想要了解如何在孩子(或孙子或曾孙)更新时更新父组件的任何其他人,请参阅我对其他类似问题的回答:

Re-initializing class on redirect

如果仍然保留当前的组件层次结构,当 UsersContainer 更新时,其子组件( UsersListContainer AddUserContainer )将是也更新了。但是, AddUserContainer 将再次更新!

因此,我仍然认为在你的情况下,使用Flux或Redux是一个很好的接近,这消除了通过多层次深度和过度道具传递道具的复杂性。复杂的组件层次结构