强制 React 容器刷新数据

IT技术 reactjs
2021-04-04 10:21:31

在我的 React 应用程序中,我有两种不同类型的组件:演示文稿容器它大致是在 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 } />
  }
}

但是这种方法感觉像是误用了keyprops。有没有更好/更优雅的方法来做到这一点?

2个回答

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

它还可以让您处理加载和错误状态,这对于当今一个体面的 Web 应用程序来说绝对是必要的。

在下面的示例中,我摆脱了UsersListContainer但也AddUserContainer进入UsersContainer了。这使您UsersListView成为UsersContainer. 随意更改命名。这样我就可以让refreshUsersprops传入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);

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

谢谢你的建议!它给了我一些关于使用高阶组件来显示加载动画等的好主意。
2021-06-11 10:21:31

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

在我看来,React 的主要思想是将 props 从父级传递给子级,因此,Irvin Lim 的“摆脱了 UsersListContainer 但将 AddUserContainer 移动到 UsersContainer”的想法将使您更容易控制何时更新您的组件!

你目前的做法和我的想法是一样的:在你的UsersContainer 中,创建一个方法来强制更新它,然后将它传递给AddUserContainer,在这个 AddUserContainer 添加一个用户之后,你在父级上触发该更新方法:

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

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

重定向时重新初始化类

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

因此,我仍然认为在你的情况下,使用 Flux 或 Redux 是一个很好的方法,它消除了通过多个深层次和复杂的组件层次结构传递props的复杂性