M
M
miniven2018-06-01 11:17:15
JavaScript
miniven, 2018-06-01 11:17:15

Why does a component get its old value after updating a property in a Redux store?

I store the pages property in the Redux store. There is an action that changes this property.
There is also an asynchronous action that sends a request to the server with the pages parameter from the store. This happens as follows: the user presses the button, two dispatch's are called: the first one changes the pages property, the second one makes an asynchronous request based on the pages property. The problem is that the second action (like the entire component at the time of the dispatch) gets the old pages value. Although, the first one, as far as I understand, is not asynchronous. And they are called in the correct order. What could be the problem?
Component code:

import React, { Component } from 'react';
import { connect } from 'react-redux';

// Components //

import ReactPaginate from 'react-paginate';

// Actions //

import { searchPosts } from '../../actions/posts';
import { setSelectedPage } from '../../actions/pages';

class App extends Component {
  state = {
    filterData: {
      title: '',
      author: null,
      before: null,
      after: null,
    },
  }

  setSelectedPage = (selectedPage) => {
    this.props.setSelectedPage(selectedPage + 1);
  }

  searchPosts = () => {
    const { selectedPage } = this.props.pages;
    const { filterData } = this.state;
    const { before, after, title, author } = filterData;

    const beforeISO = before && before.isValid() ? before.toISOString() : null;
    const afterISO = after && after.isValid() ? after.toISOString() : null;

    this.props.searchPosts({
      title,
      author,
      before: beforeISO,
      after: afterISO,
      page: selectedPage,
    });
  }

  render() {
    return (
      <section>
        <ReactPaginate
          onPageChange={({ selected }) => {
            this.setSelectedPage(selected);
            this.searchPosts();
          }}
        />
      </section>
    );
  }
};

const mapStateToProps = state => ({
  posts: state.posts,
  pages: state.pages,
});

export default connect(mapStateToProps, { searchPosts, setSelectedPage })(App);

Action code:
import { SET_SELECTED_PAGE } from '../types/pages';
import { SET_POSTS, SET_TOTAL_POSTS } from '../types/posts';
import API from '../api/api';

export const setSelectedPage = selected => ({
  type: SET_SELECTED_PAGE,
  selectedPage: selected,
});

export const searchPosts = (payload) => (dispatch) => {
  return API.posts.searchPosts(payload)
    .then(response => {
      dispatch(setTotalPosts(Number(response.headers['x-wp-total'])));

      return response.data;
    })
    .then(data => {
      dispatch(setPosts(data));
    });
};

Reducer code:
import { SET_SELECTED_PAGE } from '../types/pages';

const initialState = {
  postsPerPage: 12,
  selectedPage: 1,
};

const pagesReducer = (state = initialState, { type, selectedPage }) => {
  switch (type) {
    case SET_SELECTED_PAGE:
      return {
        ...state,
        selectedPage,
      };
    default:
      return state;
  }
};

export default pagesReducer;

Answer the question

In order to leave comments, you need to log in

1 answer(s)
M
Maxim, 2018-06-01
@miniven

The old props are used, the new one has not yet arrived at this moment (there was no new render yet).
In general, all this can be done in one action, there is no need to write 2 functions.
If you really want to, then transfer it this.searchPosts()to componentWillReceiveProps / getDerivedStateFromProps, but as I wrote above, it's better to do everything in one request.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question