React Redux - как загрузить детали, если массив еще не получен? - PullRequest
0 голосов
/ 29 октября 2018

У меня есть приложение с избыточностью и маршрутизатором, где при первой загрузке загружаются все пользователи. Для этого я реализовал основной компонент, который загружает пользователя при монтировании компонента:

class Content extends Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {
    this.props.load();
  }

  render() {
    return this.props.children;
  }
}

В последующем, если пользователь решит загрузить данные одного пользователя, данные также будут получены через тот же спасательный крюк:

class Details extends Component {
  componentDidMount() {
    this.props.getByUrl(this.props.match.params.url);
  }

  render() {
    const { user: userObject } = this.props;
    const { user } = userObject;

    if (user) {
      return (
        <>
          <Link to="/">Go back</Link>
          <h1>{user.name}</h1>
        </>
      );
    }
    return (
      <>
        <Link to="/">Go back</Link>
        <div>Fetching...</div>
      </>
    );
  }

Теперь это работает хорошо, если пользователь попадает на главную страницу. Однако, если вы перейдете непосредственно к ссылке (т.е. https://43r1592l0.codesandbox.io/gal-gadot), это не так, потому что пользователи еще не загружены.

Я сделал простой пример, чтобы продемонстрировать свои проблемы. https://codesandbox.io/s/43r1592l0 если вы нажмете на ссылку, это работает. Если вы попадаете прямо по ссылке (https://43r1592l0.codesandbox.io/gal-gadot), это не так.

Как бы я решил эту проблему?

1 Ответ

0 голосов
/ 30 октября 2018

Сводка нашего чата на реактивлюкс:

Чтобы ответить на ваш вопрос: как бы вы решили это? -> Компоненты высокого порядка

Ваш вопрос сводится к тому, чтобы "повторно использовать выборку всех пользователей перед загрузкой компонента".

Допустим, вы хотите показать Компонент после загрузки ваших пользователей, в противном случае вы показываете загрузочный div: (Простая версия)

import {connect} из'act-redux '

const withUser = connect(
  state => ({
    users: state.users // <-- change this to get the users from the state
  }),
  dispatch => ({
    loadUsers: () => dispatch({type: 'LOAD_USERS'}) // <-- change this to the proper dispatch
  })
)

теперь вы можете повторно использовать withUsers для обоих ваших компонентов, что будет выглядеть так:

class Content extends Component {
  componentDidMount() {
    if (! this.props.users || ! this.props.users.length) {
      this.props.loadUsers()
    }
  }
  // ... etc
}

const ContentWithUsers = withUsers(Content) // <-- you will use that class

class Details extends Component {
  componentDidMount() {
    if (! this.props.users || ! this.props.users.length) {
      this.props.loadUsers()
    }
  }  
}

const DetailsWithUsers = withUsers(Details) // <-- same thing applies

мы теперь создали повторно используемый HOC от connect. вы можете обернуть ваши компоненты с помощью withUsers, а затем использовать его повторно, но, как видите, вы также дважды переписываете компонент componentDidMount ()

давайте возьмем фактическую load if we haven't loaded it часть вашего компонента и поместим ее в оболочку

const withUsers = WrappedComponent => { // notice the WrappedComponent
  class WithUsersHOC extends Component {
    componentDidMount () {
      if (!this.props.users || !this.props.users.length) {
        this.props.loadUsers()
      }
    }

    render () {
      if (! this.props.users) { // let's show a simple loading div while we haven't loaded yet
        return (<div>Loading...</div>)
      }
      return (<WrappedComponent {...this.props} />) // We render the actual component here
    }
  }
  // the connect from the "simple version" re-used
  return connect(
    state => ({
      users: state.users
    }),
    dispatch => ({
      loadUsers: () => dispatch({ type: 'LOAD_USERS' })
    })
  )(WithUsersHOC)
}

Теперь вы можете просто сделать:

class Content extends Component {
  render() {
    // ......
  }
}
const ContentWithUsers = withUsers(Content)

Больше не нужно загружать пользователей, поскольку WithUsersHOC позаботится об этом

Теперь вы можете обернуть Content и Details одним и тем же HOC (High Order Component)

Пока пользователи не будут загружены, пока не будет показан фактический компонент. После загрузки пользователей ваши компоненты отображаются правильно.

Нужна еще одна страница, где вам нужно загрузить пользователей перед отображением? Оберните это также в свой HOC

теперь, еще одна вещь, которая вдохновляет на повторное использование

Что если вы не хотите, чтобы ваш компонент withLoading мог просто обрабатывать пользователей?

const withLoading = compareFunction = Component =>
  class extends React.Component {
    render() {
      if (! compareFunction(this.props)) {
        return <Component {...this.props} />;
      }
      else return <div>Loading...</div>;
    }
  };

теперь вы можете использовать его снова:

const withUsersLoading = withLoading(props => !props.users || ! props.users.length)
const ContentWithUsersAndLoading = withUsers(withUsersLoading(Content)) // sorry for the long name

или, написано как немного более чистая композиция:

export default compose(
  withUsers,
  withLoading(props => !props.users || !props.users.length)
)(Content)

теперь у вас есть и withUsers, и withLoading для повторного использования в вашем приложении

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...