前面我们把首页的功能完成了,现在我们做一下性能调优,与跳转到详情页面。
首先,我们看到 src/pages/home 下面几乎所有组件,都调用了react-redux 的 connect 方法 与 store 做了连接。
这就会有一个问题,只要store 发生了改变,这些组件就都会被重新渲染。
那我们可以使用一个生命周期函数 shouldComponentUpdate 中判断,只有在与本组件相关数据变化时,才会更新。
当然,React 中提供了新的组件类型,使得我们可以省略在每个组件中使用 shouldComponentUpdate 的繁琐步骤。这种组件类型是PureComponent .
我们把 src/pages/home 下面的组件 extands 都改为 PureComponent 。如下
import React, {PureComponent} from 'react';
import { connect } from 'react-redux';
import {HomeWrapper, HomeLeft, HomeRight, BackTop } from './style';
import List from './components/List';
import Recommend from './components/Recommend';
import Topic from './components/Topic';
import Writer from './components/Writer';
import bannerImage from '../../statics/ooo.jpg';
import { actionCreators } from './store';
class Home extends PureComponent {
handleScrollTop () {
window.scrollTo(0,0);
}
render () {
return (
<HomeWrapper>
<HomeLeft>
<img
className="banner-img"
src={bannerImage}
alt=''
/>
<Topic></Topic>
<List></List>
</HomeLeft>
<HomeRight>
<Recommend></Recommend>
<Writer></Writer>
</HomeRight>
{this.props.showScroll ? <BackTop onClick={this.handleScrollTop}>顶部</BackTop> : null }
</HomeWrapper>
)
}
componentDidMount () {
this.props.changeHomeData();
this.bindEvents();
}
bindEvents() {
window.addEventListener("scroll", this.props.changeScrollTopShow);
}
componentWillUnmount () {
window.removeEventListener("scroll", this.props.changeScrollTopShow);
}
}
const mapState = (state) => {
return {
showScroll: state.get("home").get("showScroll")
}
}
const mapDispatch = (dispatch) => {
return {
changeHomeData () {
const action = actionCreators.getHomeInfo();
dispatch(action);
},
changeScrollTopShow () {
console.log();
if ( document.documentElement.scrollTop > 100) {
dispatch(actionCreators.toggleShowScroll(true));
} else {
dispatch(actionCreators.toggleShowScroll(false));
}
}
}
}
export default connect(mapState, mapDispatch)(Home);
其它组件同理。
注意,这里之所以可以正确使用 PureComponent 是因为我们的数据,使用了一个数据框架 immutable.js 。它保证了我们的数据是 immutable 的。PureComponent 与 immutable.js 数据管理相结合,PureComponent 使用起来就没有问题。如果在项目里,没有使用 immutable.js 管理数据,PureComponent 使用的时候就可能会遇到坑。
下面我们来实现,点击 List 中的 项目 跳转到详情页面。
打开 src/pages/home/components 下的 List.js
可以像下面这样,使用<a>标签
import React, {PureComponent} from 'react';
import { connect } from 'react-redux';
import { ListItem, ListInfo, LoadMore } from '../style';
import { actionCreators } from '../store';
class List extends PureComponent {
render () {
const { articleList, getMoreList, articlePage } = this.props;
return (
<div>
{
articleList.map( (item) => {
return (
<a key={item.get("id")} href="/detail">
<ListItem key={item.get('id')}>
<img
className='pic'
src={item.get('imgURL')}
alt=''
/>
<ListInfo>
<h3 className='title'>{item.get('title')}</h3>
<p className='desc'>{item.get('desc')}</p>
</ListInfo>
</ListItem>
</a>
)
} )
}
<LoadMore onClick={ () => getMoreList(articlePage)}>更多文字</LoadMore>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
articleList: state.get("home").get("articleList"),
articlePage: state.get("home").get("articlePage")
}
};
const mapDispatchToProps = (dispatch) => {
return {
getMoreList (page) {
dispatch(actionCreators.getMoreList(page));
}
}
};
export default connect(mapStateToProps, mapDispatchToProps)(List);
但是这样,点击链接的时候,就会重新发送获取页面的请求,这样就不是单页面程序。再发送请求会耗掉一部分性能。我们使用react-router-dom,如下。
import React, {PureComponent} from 'react';
import { connect } from 'react-redux';
import { ListItem, ListInfo, LoadMore } from '../style';
import { actionCreators } from '../store';
import { Link } from "react-router-dom";
class List extends PureComponent {
render () {
const { articleList, getMoreList, articlePage } = this.props;
return (
<div>
{
articleList.map( (item) => {
return (
<Link key={item.get("id")} to="/detail">
<ListItem key={item.get('id')}>
<img
className='pic'
src={item.get('imgURL')}
alt=''
/>
<ListInfo>
<h3 className='title'>{item.get('title')}</h3>
<p className='desc'>{item.get('desc')}</p>
</ListInfo>
</ListItem>
</Link>
)
} )
}
<LoadMore onClick={ () => getMoreList(articlePage)}>更多文字</LoadMore>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
articleList: state.get("home").get("articleList"),
articlePage: state.get("home").get("articlePage")
}
};
const mapDispatchToProps = (dispatch) => {
return {
getMoreList (page) {
dispatch(actionCreators.getMoreList(page));
}
}
};
export default connect(mapStateToProps, mapDispatchToProps)(List);