erikras / react-redux-universal-hot-example

A starter boilerplate for a universal webapp using express, react, redux, webpack, and react-transform
MIT License
12.01k stars 2.5k forks source link

Redux action got delayed. #1370

Open ducnvhn opened 7 years ago

ducnvhn commented 7 years ago

I am trying to implement infinite scroll on my component. When user scroll to the bottom of the page, it will automatically load more article from API server. But the Redux action seem to be delayed few seconds. Here is the code of the redux :

const LOAD = 'redux-example/articles/LOAD';
const LOAD_SUCCESS = 'redux-example/articles/LOAD_SUCCESS';
const LOAD_FAIL = 'redux-example/articles/LOAD_FAIL';

const initialState = {
  loaded: false,
  data: [],
};
export default function reducer(state = initialState, action = {}) {
  switch (action.type) {
    case LOAD:
      return {
        ...state,
        loading: true,
        error: null
      };
    case LOAD_SUCCESS:
      const { data } = state;
      const newData = data.concat(action.result);

      return {
        loading: false,
        loaded: true,
        error: null,
        data: newData
      };
    case LOAD_FAIL:
      return {
        ...state,
        loading: false,
        loaded: true,
        data: null,
        error: action.error
      };
    default:
      return state;
  }
}
export function load(page = 0) {
  return {
    types: [LOAD, LOAD_SUCCESS, LOAD_FAIL],
    promise: (client)=>client.post('/articles/paginate', {
      data: {page}
    })
  };
}
export function isLoaded(globalState) {
  return globalState.articles && globalState.articles.loaded;
}

Here is the code of the component that call the load action when scroll reached bottom.

`import React, { Component, PropTypes } from 'react';
import { Row, Col } from 'react-bootstrap';
import * as acticleActions from 'redux/modules/questions';
import {connect} from 'react-redux';
import { load as loadArtices, isLoaded as isArticlesLoaded } from 'redux/modules/questions';
import { asyncConnect } from 'redux-async-connect';
import SingleArticle from './HomeComps/SingleArticle';

@asyncConnect([{
  deferred: true,
  promise: ({store: {dispatch, getState}}) => {
    if (!isArticlesLoaded(getState())) {
      return dispatch(loadArtices());
    }
  }
}])
@connect(
  state => ({
    articles: state.articles.data,
    error: state.articles.error,
    loading: state.articles.loading
  }), {...acticleActions})
export default class Home extends Component {
  static propTypes = {
    articles: PropTypes.array,
    error: PropTypes.object,
    loading: PropTypes.bool,
    load: PropTypes.func.isRequired,
  };

  constructor(props) {
    super(props);
    this.state = {
      currentPage: 0,
    };
    this.nextPage = this._nextPage.bind(this);
    this.handleScroll = this.handleScroll.bind(this);
  }

  componentDidMount() {
    window.addEventListener('scroll', this.handleScroll);
  }

  componentWillUnmount() {
    window.removeEventListener('scroll', this.handleScroll);
  }

  handleScroll() {
    const windowHeight = 'innerHeight' in window ? window.innerHeight : document.documentElement.offsetHeight;
    const body = document.body;
    const html = document.documentElement;
    const docHeight = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
    const windowBottom = windowHeight + window.pageYOffset;
    if (windowBottom >= docHeight) {
      console.log('load nex page'); // I see the console immediately when the scroll reached bottom
      this.nextPage(); //  but this action seem to delayed few seconds. 
    } else {
      // console.log(' Do nothing ...');
    }
  }

  _nextPage() {
    const currentPage = this.state.currentPage;
    this.setState({
      currentPage: currentPage + 1
    }, ()=> {
      this.props.load(this.state.currentPage);
    });
  }

  render() {
    const sidebarStyle = {marginTop: '4em'};
    return (
      <Row>
        <Helmet title="Home Page"/>
        <Col xs={12} sm={12} md={6}>
          <h5> Articles List </h5>
          { this.props.articles &&
          this.props.articles.map((article, index)=>
            <SingleArticle article={article} key = {index}/>
          )
          }
          <div style={{marginBottom: '1em', textAlign: 'center'}}>
            { this.props.loading && <p style = {{textAlign: 'center'}}> Loading...</p> }
            {/* The loading text above is delayed few seconds */}
          </div>
        </Col>
      </Row>
    );
  }
}`

I tried to inspect the redux dev tool (Google Chrome) and found that the redux state change to loading:true was delayed. Can someone please help to tell me what should I do get it fire the action immediately after the scroll reaching to bottom?