从服务器加载时在React组件上呈现占位符项目

时间:2018-08-23 12:57:30

标签: javascript reactjs react-redux mern

我正在开发一个MERN应用程序,人们可以在其中添加用户创建的内容。我已经合并了基本的加载功能,以便在从服务器获取数据时向用户提供反馈。但是,我希望能够进行一些改进以提高性能并减少加载时间。

我目前的做法:

作为示例,我将解释我的PostComponent,它将通过分派的redux动作(getPosts)从数据库请求用户创建的帖子。这些帖子呈现在子组件PostFeed中,然后映射到各个PostItem组件中。

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import PostForm from './PostForm';
import PostFeed from './PostFeed';
import Spinner from '../common/Spinner';
import { getPosts } from '../../actions/postActions';

class Posts extends Component {
  componentDidMount() {
    this.props.getPosts();
  }

  render() {
    const { posts, loading } = this.props.post;
    let postContent;

    if (posts === null || loading) {
      postContent = <Spinner />;
    } else {
      postContent = <PostFeed posts={posts} />;
    }

    return (
      <div className="feed">
        <div className="container">
          <div className="row">
            <div className="col-md-12">
              <PostForm />
              {postContent}
            </div>
          </div>
        </div>
      </div>
    );
  }
}

Posts.propTypes = {
  getPosts: PropTypes.func.isRequired,
  post: PropTypes.object.isRequired
};

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

export default connect(mapStateToProps, { getPosts })(Posts);

在帖子发布之前,我将布尔加载设置为true。获取所有帖子后,将加载再次设置为false。上面组件中的if语句正在渲染一个微调器,它是一个.gif文件或PostFeed组件,具体取决于加载布尔值的状态。

postActions:

...
export const setPostLoading = () => {
  return {
    type: POST_LOADING,
  };
};

export const getPosts = () => (dispatch) => {
  dispatch(setPostLoading());
  axios
    .get('/api/posts')
    .then(res => dispatch({
      type: GET_POSTS,
      payload: res.data,
    }))
    .catch(err => dispatch({
      type: GET_POSTS,
      payload: null,
    }));
};
...

postReducer:

...
export default function (state = initialState, action) {
  switch (action.type) {
    case POST_LOADING:
      return {
        ...state,
        loading: true,
      };
    case GET_POSTS:
      return {
        ...state,
        posts: action.payload,
        loading: false,
      };
...

这一切都可以正常工作,但是我对此方法有两个担忧:

首先,在加载组件时使用微调器会使事情在页面上有些跳动。虽然不一定是一件坏事,但我想创造最无缝的用户体验,并发现实现占位符是一种更优雅的解决方案。

Placeholder Loading Example

如何为每个单独的组件实现占位符项,以使内容在加载时不会跳动并保持良好位置?

第二,加载帖子时,它正在加载存储在数据库中的所有可用帖子。我可以想象,当发布过多的帖子时,加载所有单个PostItem可能会花费很长时间,并且会占用很多不必要的带宽。

如何添加仅加载浏览器窗口中显示的内容的功能,以便在用户向下滚动时加载更多内容?可能是滚动事件处理程序?但是,如何确定要渲染哪个PostItem以及保留哪个占位符?

希望我已经解释得很清楚了,它仍然是相对较新的反应/ redux,因此这里可能会出现一些错误。欢迎任何提示,建议或最佳做法。

非常感谢!

1 个答案:

答案 0 :(得分:1)

您在这里问了很多问题。首先,听起来您已经需要为每个组件显示“骨架”,并且好消息是有多种解决方案可用,例如react-content-loader使用可定制的SVG,react-placeholder ,(或者您可以使用react-transition-group进行滚动。文档将说明如何根据需要管理每个组件的过渡。

关于从axios API调用返回的项目“过多”,如果不知道一个粗糙的数字(100、1000,更多等),并且发现性能问题,就很难说。您要返回多少数据。如果数字最终有问题,那么您所寻找的就是“虚拟(或无限)滚动”和分页,即您不是一次请求所有数据,而是成块请求。例如,StackOverflow使用分页,新的Reddit使用无限滚动。同样,也有NPM软件包,例如react-tiny-virtual-list