通过手动编写skeleton,在fetch数据时显示skeleton loading,数据拉取成功隐藏skeleton
先看下效果图
在component下创建页面对应的skeleton,然后通过在index.js中export输出,在需要使用skeleton的页面中引入。
代码结构
charity-web
|--- components
|---Skeleton
|---HomeProject.js home页项目列表
|---index.js 导出所有skeleton
|---ProjectCard.js 项目列表item
|---HomeListing.js 项目列表页
|--- pages
|---index.js
|---listing.js
|--- redux
|---app
|---project
|---index.js
|---rootSaga.js
skeleton部分代码
- skeleton/index.js文件
import HomeProjectSkeleton from './HomeProject'
import ProjectListingSkeleton from './ProjectListing'
import PromotionItemSkeleton from './PromotionItem'
export { PromotionItemSkeleton, HomeProjectSkeleton, ProjectListingSkeleton }
- skeleton/homeproject.js文件
import { Col, Row } from 'antd'
import React, { Component } from 'react'
import styled from 'styled-components'
import mediaQuery from '../../utils/mediaQuery'
import ProjectCard from './ProjectCard'
const Container = styled.div`
.projects {
padding-top: 32px;
${mediaQuery.tablet} {
padding-top: 24px;
}
${mediaQuery.mobile} {
padding-top: 24px;
}
}
.projectWrapper {
padding-bottom: 24px;
}
`
class HomeProject extends Component {
render() {
const items = [0, 1, 2, 3, 4]
return (
<Container>
<div className='projects'>
<div className='max-width'>
<Row type='flex' justify='start' gutter={24}>
{items.map(i => {
return (
<Col
xs={24}
md={12}
xl={8}
className='projectWrapper'
key={`p_${i}`}
>
<ProjectCard />
</Col>
)
})}
</Row>
</div>
</div>
</Container>
)
}
}
export default HomeProject
- skeleton/projectlisting.js文件
import { Col, Row } from 'antd'
import React, { Component } from 'react'
import ProjectCard from './ProjectCard'
class ProjectListing extends Component {
render() {
const items = [0, 1, 2, 3, 4]
return (
<Row type='flex' justify='start' gutter={24}>
{items.map(i => {
return (
<Col
xs={24}
md={24}
xl={24}
className='projectWrapper'
key={`p_${i}`}
>
<ProjectCard listStyle />
</Col>
)
})}
</Row>
)
}
}
export default ProjectListing
- skeleton/promotionitem.js文件
import React, { Component } from 'react'
import styled from 'styled-components'
import mediaQuery from '../../utils/mediaQuery'
const Container = styled.div`
100vw;
height: 37.5vw;
background-color: #f4f4f4;
${mediaQuery.mobile} {
height: 56.25vw;
}
`
class PromotionItem extends Component {
render() {
return <Container />
}
}
export default PromotionItem
在页面中应用skeleton
1、首先引入skeleton
import {
HomeProjectSkeleton,
PromotionItemSkeleton
} from '../components/Skeleton/index'
2、在render函数中,通过 this.props.isFetching判断是否显示skeleton
{process.env.usePromoItem ? (
this.props.isFetching ? (
<PromotionItemSkeleton />
) : (
<Swiper slides={this.props.promoItems} />
)
) : (
this.renderHeroProject()
)}
{this.props.isFetching ? (
<HomeProjectSkeleton />
) : (
(this.renderHighlightedProjects(), this.renderOtherProjects())
)}
3、在reduces.js中,当getHomePageDataRequest拉取数据的时候,设置isFetching为true,getHomePageDataSucceeded获取成功后,将isFetching修改为false
import {
getHomePageDataRequest,
getHomePageDataSucceeded,
} from './actions'
export const projectInitialState = {
fetching: {
getHomepageData: false,
getSearchListingPageData: false
}
}
const projectReducer = handleActions(
{
[getHomePageDataRequest]: state => {
return {
...state,
fetching: {
getHomepageData: true
}
}
},
[getHomePageDataSucceeded]: (state, action) => {
return {
...state,
fetching: {
getHomepageData: false
}
}
},
}
projectInitialState
)
export default projectReducer
4、这样,在页面中mapStateToProps中我们可以拿到isFetching的状态,从而在数据获取成功之前显示skeleton
const mapStateToProps = ({ appState, projectState, paymentState }, props) => ({
isFetching: projectState.fetching.getHomepageData
})
总结
以上,就是对skeleton在项目中的应用,当然通过以上这种方式实现的skeleton,有一个不好的地方是,如果页面结构变化,我们同时也需要更新sekleton的结构,这是比较麻烦的地方。