Ждите Redux Thunk в реактивном жизненном цикле - PullRequest
0 голосов
/ 13 декабря 2018

Я работал с React & Redux некоторое время, когда коллега по работе увидел какой-то код, который я написал, и прокомментировал его.

SomeComponent.js

class SomeComponent extends Component {

  async componentDidMount() {
    await this.props.fetchPosts();  

    if (this.props.posts.length < 1)
      return navigateTo( /* someOtherPlace */);
  }

  render() {
    return (
        <>
          {this.props.posts.map(
            (postData, i) => <Post key={i} {...postData}/>
          )}
        </>
    );
  }
}

const mapStateToProps = ({ posts }) => ({
  posts: posts.list,
  isFetching: posts.isFetching
});

export default connect(mapStateToProps, { fetchPosts })(SomeComponent);

actions / posts.js

export const fetchPosts = () => async dispatch => {
  dispatch(requestPosts());
  let posts;
  try {
    posts = (await api.get('/posts')).data
  } catch (e) {
    posts = e;
  }
  dispatch(receivePosts(posts));
}

Он в основном сказал, что я не должен ждать действия fetchPosts(), вместо этого я должен просто позвонитьэто, и пусть он обновляет реквизиты, повторно визуализирует и выполняет условную навигацию в componentDidUpdate, что, когда он сказал это, это имело для меня смысл.

Но теперь я продолжаю спрашивать себя, что я делална самом деле это было плохо, потенциально глючно или просто плохая практика, которая добавляла больше сложности.

Он не упомянул причины, по которым это было неправильно, за исключением того, что это не был способ реагирования.

РЕДАКТИРОВАТЬ: Добавлен фрагмент кода, показывающий, что подход действительно работает и не выполняет ошибочное чтение.

Edit Await in componentDidMount

1 Ответ

0 голосов
/ 13 декабря 2018

Таким образом, в вашем случае есть небольшая проблема

async componentDidMount() {
    await this.props.fetchPosts();  

    if (this.props.posts.length < 1)
      return navigateTo( /* someOtherPlace */);
}

Здесь await будет ожидать завершения fetchPosts, если вернет обещание.Теперь fetchPosts отправит действие, которое приведет только к обновлению реквизита и запуску другого рендера для обновления сообщений в компоненте.Таким образом, даже если вы ждете, пока fetchPosts завершит posts, не будут обновлены в одном и том же цикле рендеринга, и, следовательно, использование this.props.posts.length не вернет вам результат, соответствующий последнему обновлению сообщений в избыточном хранилище.В результате вы излишне ждете завершения fetchPosts и выполняете проверку, которая приведет к ошибочному результату

Лучший подход - работать как

class SomeComponent extends Component {

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

  componentDidUpdate(prevProps) {
     if(this.props.posts !== prevProps.posts && this.props.posts.length < 1) {
          return navigateTo( /* someOtherPlace */);
     }
  }

  render() {
    return (
        <>
          {this.props.posts.map(
            (postData, i) => <Post key={i} {...postData}/>
          )}
        </>
    );
  }
}
...