美文网首页
React 16.4 开发简书项目[8]

React 16.4 开发简书项目[8]

作者: Mark同学 | 来源:发表于2019-11-28 23:33 被阅读0次

第8章 项目实战:首页开发

8-1 什么是路由,如何在React中使用路由功能

npm i react-router-dom

src
——App.js

import React from 'react';
import { Provider } from 'react-redux';
import { BrowserRouter, Route } from 'react-router-dom';
import { GlobalStyle } from './style';
import Header from './common/header';
import store from './store';

function App() {
  return (
    <Provider store={store}>
      <GlobalStyle />
      <Header />
      <BrowserRouter>
        <Route path='/' exact render={()=><div>home</div>}></Route>
        <Route path='/detail' exact render={()=><div>detail</div>}></Route>
      </BrowserRouter>
    </Provider>
  );
}

export default App;

8-2 首页组件的拆分

1.定义 Home 组件

src
——pages
————home
——————index.js

import React from 'react';

function Home() {
  return (
    <div>-Home-</div>
  );
}

export default Home;

2.定义 Detail 组件

src
——pages
————detail
——————index.js

import React from 'react';

function Detail() {
  return (
    <div>-Detail-</div>
  );
}

export default Detail;

3.引入 Home 和 Detail 组件

src
——App.js

import React from 'react';
import { Provider } from 'react-redux';
import { BrowserRouter, Route } from 'react-router-dom';
import Header from './common/header';
import Home from './pages/home';
import Detail from './pages/detail';
import { GlobalStyle } from './style';
import store from './store';

function App() {
  return (
    <Provider store={store}>
      <GlobalStyle />
      <Header />
      <BrowserRouter>
        <Route path='/' exact component={Home}></Route>
        <Route path='/detail' exact component={Detail}></Route>
      </BrowserRouter>
    </Provider>
  );
}

export default App;

4.定义 Home 组件的样式

src
——pages
————home
——————style.js

import styled from 'styled-components';

export const HomeWrapper = styled.div`
  overflow: hidden;
  width: 960px;
  margin: 0 auto;
`;

export const HomeLeft = styled.div`
  float: left;
  margin-left: 15px;
  padding-top: 30px;
  width: 625px;
  .banner-img {
    width: 625px;
    height: 270px;
  }
`;

export const HomeRight = styled.div`
  width: 240px;
  float: right;
`;

5.在 Home 组件中引入样式

src
——pages
————home
——————index.js

import React from 'react';
import { 
  HomeWrapper,
  HomeLeft,
  HomeRight
} from './style';

function Home() {
  return (
    <HomeWrapper>
      <HomeLeft>
        <img className="banner-img" src="//upload.jianshu.io/admin_banners/web_images/4318/60781ff21df1d1b03f5f8459e4a1983c009175a5.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/1250/h/540" alt=""/>
      </HomeLeft>
      <HomeRight></HomeRight>
    </HomeWrapper>
  );
}

export default Home;

6.拆分 Home 页面的组件

src
——pages
————home
——————components
————————Topic.js

import React from 'react';

function Topic() {
  return (
    <div>-Topic-</div>
  );
}

export default Topic;

————————List.js

import React from 'react';

function List() {
  return (
    <div>-List-</div>
  );
}

export default List;

————————Recommend.js

import React from 'react';

function Recommend() {
  return (
    <div>-Recommend-</div>
  );
}

export default Recommend;

————————Writer.js

import React from 'react';

function Writer() {
  return (
    <div>-Writer-</div>
  );
}

export default Writer;

7.在 Home 组件中引入四个子组件

src
——pages
————home
——————index.js

import React from 'react';
import Topic from './components/Topic';
import List from './components/List';
import Recommend from './components/Recommend';
import Writer from './components/Writer';

import { 
  HomeWrapper,
  HomeLeft,
  HomeRight
} from './style';

function Home() {
  return (
    <HomeWrapper>
      <HomeLeft>
        <img className="banner-img" src="//upload.jianshu.io/admin_banners/web_images/4318/60781ff21df1d1b03f5f8459e4a1983c009175a5.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/1250/h/540" alt=""/>
        <Topic />
        <List />
      </HomeLeft>
      <HomeRight>
        <Recommend></Recommend>
        <Writer></Writer>
      </HomeRight>
    </HomeWrapper>
  );
}

export default Home;

8-3 首页专题区域布局及reducer的设计

immutable 对象的获取方式

\color{red}{注意:如果获取的是列表数据结构,并且列表里面是 JS 对象}
列表循环的获取方式要改为:item.get('imgUrl'),不能为点语法,切记!!!不要忘记!!!
mapStateToProps里的获取方式为:list: state.home.get('blogList')

src
——pages
————home
——————components
————————Topic.js

import React from 'react';
import { TopicWrapper, TopicItem } from '../style';

function Topic() {
  return (
    <TopicWrapper>
     <TopicItem>
        <img className='topic-pic' src='//upload.jianshu.io/collections/images/261938/man-hands-reading-boy-large.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/64/h/64' alt=''/>
        社会热点
     </TopicItem>
    </TopicWrapper>
  );
}

export default Topic;

1.将子组件的样式放到 Home 组件的样式里一起管理

src
——pages
————home
——————style.js


// ...

export const TopicWrapper = styled.div`
  overflow: hidden;
  padding: 20px 0 10px 0;
  margin-left: -18px;
  border-bottom: 1px solid #dcdcdc;
`;

export const TopicItem= styled.div`
  float: left;
  height: 32px;
  line-height: 32px;
  margin-left: 18px;
  margin-bottom: 18px;
  padding-right: 10px;
  background: #f7f7f7;
  font-size: 14px;
  color: #000;
  border: 1px solid #dcdcdc;
  border-radius: 4px;
  .topic-pic {
    display: block;
    float: left;
    width: 32px;
    height: 32px;
    margin-right: 10px;
  }
`;

2.TopicItem 应该是列表数据循环出来的

src
——pages
————home
——————store
————————reducer.js

import { fromJS } from 'immutable';

const defaultState = fromJS({
  topicList: [{
    id: 1,
    title: '社会热点',
    imgUrl: '//upload.jianshu.io/collections/images/261938/man-hands-reading-boy-large.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/64/h/64'
  },{
    id: 2,
    title: '手绘',
    imgUrl: '//upload.jianshu.io/collections/images/21/20120316041115481.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/64/h/64'
  }]
});

export default (state = defaultState, action) => {
  switch(action.type) {
    default:
      return state;
  }
};

src
——pages
————home
——————store
————————index.js

import reducer from './reducer';

export { reducer };

3.引用 Home 的 Reducer

src
———store
————reducer.js

import { combineReducers } from 'redux-immutable';
import { reducer as headerReducer } from '../common/header/store';
import { reducer as homeReducer} from '../pages/home/store';

const reducer = combineReducers({
  header: headerReducer,
  home: homeReducer
})

export default reducer;

4.引入 Store

src
——pages
————home
——————components
————————Topic.js

import React from 'react';
import { connect } from 'react-redux';
import { TopicWrapper, TopicItem } from '../style';

function Topic(props) {
  return (
    <TopicWrapper>
      {
        props.list.map((item) => {
          return (
            <TopicItem  key={item.get('id')}>
              <img className='topic-pic' src={item.get('imgUrl')} alt=''/>
              {item.get('title')}
            </TopicItem>
          )
        })
      }
    </TopicWrapper>
  )
}

const mapState = (state) => ({
  list: state.getIn(['home', 'topicList'])
});

export default connect(mapState, null)(Topic);

8-4 首页文章列表制作

1.

src
——pages
————home
——————components
————————List.js

import React from 'react';
import { ListItem, ListInfo } from '../style';
import { connect } from 'react-redux';

function List(props) {
  return (
    <div>
      {
        props.list.map((item) => {
          return (
            <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>
         )
        })
      }
    </div>
  );
}

const mapState = (state) => ({
  list: state.getIn(['home', 'articleList'])
})

export default connect(mapState, null)(List);

2.

src
——pages
————home
——————style.js


//...

export const ListItem = styled.div`
  overflow: hidden;
  padding: 20px 0;
  border-bottom: 1px solid #dcdcdc;
  .pic {
    display: block;
    width: 125px;
    height: 100px;
    float: right;
    border-radius: 4px;
  }
`;

export const ListInfo = styled.div`
  width: 480px;
  float: left;
  padding-right: 20px;
  .title {
    line-height: 27px;
    font-size: 18px;
    font-weight: bold;
    color: #333;
  }
  .desc {
    line-height: 24px;
    font-size: 13px;
    color: #999;
  }
`;

3.

src
——pages
————home
——————store
————————reducer.js

  articleList: [{
    id: 1,
    title: '胡歌12年后首谈车祸:既然活下来了,就不能白白活着',
    desc: '文/麦大人 01 胡歌又刷屏了。 近日他上了《朗读者》,而这一期的主题是“生命”,他用磁性的嗓音,朗读了一段《哈姆雷特》中的经典独白,相当震撼:...',
    imgUrl:'https://img.haomeiwen.com/i20131416/b99eb38c969c45b9.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/360/h/240'
  }, {
    id: 2,
    title: '胡歌12年后首谈车祸:既然活下来了,就不能白白活着',
    desc: '文/麦大人 01 胡歌又刷屏了。 近日他上了《朗读者》,而这一期的主题是“生命”,他用磁性的嗓音,朗读了一段《哈姆雷特》中的经典独白,相当震撼:...',
    imgUrl:'https://img.haomeiwen.com/i20131416/b99eb38c969c45b9.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/360/h/240'
  }]

8-5 首页推荐部分代码编写

8-6 首页异步数据获取

1.定后端接口,获取真实数据

/api/home.json
{
  "sucess": true,
  "data": {
    "topicList": [],
    "articleList":  [],
    "recommendList": []
  }
}

2.创建一个 JSON 文件做接口数据的模拟

public
——api
————home.json

{
  "success": true,
  "data": {
    "topicList": [
      {
        "id": 1,
        "title": "社会热点",
        "imgUrl": "//upload.jianshu.io/collections/images/261938/man-hands-reading-boy-large.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/64/h/64"
      },
      {
        "id": 2,
        "title": "手绘",
        "imgUrl": "//upload.jianshu.io/collections/images/21/20120316041115481.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/64/h/64"
      }
    ],
    "articleList": [
      {
        "id": 1,
        "title": "胡歌12年后首谈车祸",
        "desc": "文/麦大人 01 胡歌又刷屏了。 近日他上了《朗读者》,而这一期的主题是“生命”,他用磁性的嗓音,朗读了一段《哈姆雷特》中的经典独白,相当震撼:...",
        "imgUrl": "https://img.haomeiwen.com/i2259045/2986b9be86b01f63?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240"
      },
      {
        "id": 2,
        "title": "胡歌12年后首谈车祸:既然活下来了,就不能白白活着",
        "desc": "文/麦大人 01 胡歌又刷屏了。 近日他上了《朗读者》,而这一期的主题是“生命”,他用磁性的嗓音,朗读了一段《哈姆雷特》中的经典独白,相当震撼:...",
        "imgUrl": "https://img.haomeiwen.com/i2259045/2986b9be86b01f63?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240"
      },
      {
        "id": 3,
        "title": "胡歌12年后首谈车祸:既然活下来了,就不能白白活着",
        "desc": "文/麦大人 01 胡歌又刷屏了。 近日他上了《朗读者》,而这一期的主题是“生命”,他用磁性的嗓音,朗读了一段《哈姆雷特》中的经典独白,相当震撼:...",
        "imgUrl": "https://img.haomeiwen.com/i2259045/2986b9be86b01f63?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240"
      },
      {
        "id": 4,
        "title": "胡歌12年后首谈车祸:既然活下来了,就不能白白活着",
        "desc": "文/麦大人 01 胡歌又刷屏了。 近日他上了《朗读者》,而这一期的主题是“生命”,他用磁性的嗓音,朗读了一段《哈姆雷特》中的经典独白,相当震撼:...",
        "imgUrl": "https://img.haomeiwen.com/i2259045/2986b9be86b01f63?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240"
      }
    ]
  }
}

3.清空前端的数据

src
——pages
————home
——————store
————————reducer.js

import { fromJS } from 'immutable';

const defaultState = fromJS({
  topicList: [],
  articleList: []
});

export default (state = defaultState, action) => {
  switch(action.type) {
    default:
      return state;
  }
};

4.通过 AJAX 获取数据,改为《状态组件》

npm install axios

src
——pages
————home
——————index.js

import React, { Component } from 'react';
import { connect } from 'react-redux';
import axios from 'axios';
class Home extends Component {
  render() {
    return (
      <HomeWrapper>
        ...
      </HomeWrapper>
    );
  }

  componentDidMount() {
    axios.get('/api/home.json').then((res) => {
      const result = res.data.data;
      const action = {
        type: 'change_home_data',
        topicList: result.topicList,
        articleList: result.articleList
      }
      this.props.changeHomeData(action)
    })
  }
}

const mapDispatch = (dispatch) => ({
  changeHomeData(action) { 
    dispatch(action);
  }
});

export default connect(null, mapDispatch)(Home);

5.派发给 Store,Store 转发给 Reducer

src
——pages
————home
——————store
————————reducer.js

import { fromJS } from 'immutable';

const defaultState = fromJS({
  topicList: [],
  articleList: []
});

export default (state = defaultState, action) => {
  switch(action.type) {
    case 'change_home_data':
      return state.merge({
        topicList: fromJS(action.topicList),
        articleList: fromJS(action.articleList)
      })
    default:
      return state;
  }
};

8-7 异步操作代码拆分优化

1.UI 组件并不应该有太多业务逻辑

src
——pages
————home
——————index.js

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { actionCreators } from './store';
class Home extends Component {
  render() {
    return (
      <HomeWrapper>
        ...
      </HomeWrapper>
    );
  }

  componentDidMount() {
     this.props.changeHomeData();
  }
}

const mapDispatch = (dispatch) => ({
  changeHomeData() { 
    const action = actionCreators.getHomeInfo();
    dispatch(action);
  }
});

export default connect(null, mapDispatch)(Home);

2.在创建 Store 的地方引用 redux-thunk

npm install redux-thunk

src
——store
————index.js

import { createStore, compose, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducer';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, composeEnhancers(
  applyMiddleware(thunk)
));

export default store;

3.通过 redux-thunk 将异步放在 action 里统一管理

src
——pages
————home
——————store
————————actionCreators.js

import axios from 'axios';
import * as constants from './constants';

const changeHomeData = (result) => ({
  type: constants.CHANGE_HOME_DATA,
  topicList: result.topicList,
  articleList: result.articleList
})

export const getHomeInfo = () => {
  return (dispatch) => {
    axios.get('/api/home.json').then((res) => {
      const result = res.data.data;
      dispatch(changeHomeData(result));
    })
  }
}

src
——pages
————home
——————store
————————index.js

import reducer from './reducer';
import * as actionCreators from './actionCreators';
import * as constants from './constants';

export { reducer, actionCreators, constants };

4.

src
——pages
————home
——————store
————————constants.js

export const CHANGE_HOME_DATA = 'home/CHANGE_HOME_DATA';

5.

src
——pages
————home
——————store
————————reducer.js

import { fromJS } from 'immutable';
import * as constants from './constants';

const defaultState = fromJS({
  topicList: [],
  articleList: []
});

export default (state = defaultState, action) => {
  switch(action.type) {
    case constants.CHANGE_HOME_DATA:
      return state.merge({
        topicList: fromJS(action.topicList),
        articleList: fromJS(action.articleList)
      })
    default:
      return state;
  }
};

8-8 实现加载更多功能

1.新增加载点击事件

src
——pages
————home
——————components
————————List.js

import { ListItem, ListInfo, LoadMore } from '../style';
// ...
import { actionCreators } from '../store';

function List(props) {
  const { list, getMoreList, page } = props;
  return (
    <div>
      {
        list.map((item, index) => {
          return (
            <ListItem key={index}>
             // ...
            </ListItem>
         )
        })
      }
      <LoadMore onClick={() => getMoreList(page)}>更多文字</LoadMore>
    </div>
  );
}

const mapState = (state) => ({
  list: state.getIn(['home', 'articleList']),
  page: state.getIn(['home', 'articlePage'])
});

const mapDispatch = (dispatch) => ({
  getMoreList(page) {
    dispatch(actionCreators.getMoreList(page));
  }
});

export default connect(mapState, mapDispatch)(List);

2.定义组件样式

src
——pages
————home
——————style.js


//...

export const LoadMore = styled.div`
  width:100%;
  height: 40px;
  line-height: 40px;
  margin: 30px 0;
  background: #a5a5a5;
  text-align: center;
  border-radius: 20px;
  color: #fff;
  cursor: pointer;
`;

3.利用 redux-thunk 发送 AJAX 请求

src
——pages
————home
——————store
————————actionCreators.js

import axios from 'axios';
import * as constants from './constants';
import { fromJS } from 'immutable';


const changeHomeData = (result) => ({
 // ...
});

const addHomeList = (list, nextPage) => ({
  type: constants.ADD_ARTICLE_LIST,
  list: fromJS(list),
  nextPage
});

export const getHomeInfo = () => {
  // ...
};

export const getMoreList = (page) => {
  return (dispatch) => {
    axios.get('/api/homeList.json?page=' + page).then((res) => {
      const result = res.data.data;
      dispatch(addHomeList(result, page + 1));
    })
  }
};

4.mock 数据

public
——api
————homeList.json

{
    "success": true,
    "data": [{
            "id": 5,
            "title": "胡歌12年后首谈车祸",
            "desc": "文/麦大人 01 胡歌又刷屏了。 近日他上了《朗读者》,而这一期的主题是“生命”,他用磁性的嗓音,朗读了一段《哈姆雷特》中的经典独白,相当震撼:...",
            "imgUrl": "https://img.haomeiwen.com/i2259045/2986b9be86b01f63?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240"
        }, {
            "id": 6,
            "title": "胡歌12年后首谈车祸:既然活下来了,就不能白白活着",
            "desc": "文/麦大人 01 胡歌又刷屏了。 近日他上了《朗读者》,而这一期的主题是“生命”,他用磁性的嗓音,朗读了一段《哈姆雷特》中的经典独白,相当震撼:...",
            "imgUrl": "https://img.haomeiwen.com/i2259045/2986b9be86b01f63?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240"
        }, {
            "id": 7,
            "title": "胡歌12年后首谈车祸:既然活下来了,就不能白白活着",
            "desc": "文/麦大人 01 胡歌又刷屏了。 近日他上了《朗读者》,而这一期的主题是“生命”,他用磁性的嗓音,朗读了一段《哈姆雷特》中的经典独白,相当震撼:...",
            "imgUrl": "https://img.haomeiwen.com/i2259045/2986b9be86b01f63?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240"
        }, {
            "id": 8,
            "title": "胡歌12年后首谈车祸:既然活下来了,就不能白白活着",
            "desc": "文/麦大人 01 胡歌又刷屏了。 近日他上了《朗读者》,而这一期的主题是“生命”,他用磁性的嗓音,朗读了一段《哈姆雷特》中的经典独白,相当震撼:...",
            "imgUrl": "https://img.haomeiwen.com/i2259045/2986b9be86b01f63?imageMogr2/auto-orient/strip|imageView2/1/w/300/h/240"
        }]
}

5.

src
——pages
————home
——————store
————————constants.js

export const ADD_ARTICLE_LIST = 'home/ADD_ARTICLE_LIST';

6.加载更多 + 分页

src
——pages
————home
——————store
————————reducer.js

import { fromJS } from 'immutable';
import * as constants from './constants';

const defaultState = fromJS({
  topicList: [],
  articleList: [],
  articlePage: 1
});

export default (state = defaultState, action) => {
  switch(action.type) {
    case constants.CHANGE_HOME_DATA:
      return state.merge({
        topicList: fromJS(action.topicList),
        articleList: fromJS(action.articleList)
      });
    case constants.ADD_ARTICLE_LIST:
      return state.merge({
        articleList: state.get('articleList').concat(action.list),
        articlePage: action.nextPage
      });
    default:
      return state;
  }
};

加载更多:

  • 定义点击事件,组件样式
  • 调用 获取更多的方法
  • 发送请求,保存数据到 store
  • 在 store 更新数据

分页:

  • 在 store 里初始化页码
  • 在列表页码获取页码
  • 在事件触发的方法里传入页码
  • 在请求的 URL 里加入页码
  • 每次分发 action 的页码+1

8-9 返回顶部功能实现

1.代码量很少,直接写在 index 里

src
——pages
————home
——————index.js

//...
import { 
  HomeWrapper,
  HomeLeft,
  HomeRight,
  BackTop
} from './style';

class Home extends Component {

  handleScrollTop() {
    window.scrollTo(0, 0);
  }

  render() {
    return (
      <HomeWrapper>
        ...
       { this.props.showScroll ? <BackTop onClick={this.handleScrollTop}>Top</BackTop> : null}
      </HomeWrapper>
    );
  }

  componentDidMount() {
     //...
    this.bindEvents();
  }

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

  bindEvents() {
    window.addEventListener('scroll', this.props.changeScrollTopShow);
  }
}

const mapState = (state) => ({
  showScroll: state.getIn(['home', 'showScroll'])
})

const mapDispatch = (dispatch) => ({
  changeHomeData() { 
    //...
  },
  changeScrollTopShow() {
    if (document.documentElement.scrollTop > 400) {
      dispatch(actionCreators.toggleTopShow(true));
    } else {
      dispatch(actionCreators.toggleTopShow(false));
    }
  }
});

export default connect(mapState, mapDispatch)(Home);

2.

src
——pages
————home
——————style.js


//...

export const BackTop = styled.div`
  position: fixed;
  right: 100px;
  bottom: 100px;
  width: 60px;
  height: 60px;
  line-height: 60px;
  text-align: center;
  border: 1px solid #ccc;
  font-size: 14px;
  cursor: pointer;
`;

3.

src
——pages
————home
——————store
————————reducer.js

import { fromJS } from 'immutable';
import * as constants from './constants';

const defaultState = fromJS({
  //...
  showScroll: false
});

const changeHomeData = (state, action) => {
  return state.merge({
    topicList: fromJS(action.topicList),
    articleList: fromJS(action.articleList)
  })
}

const addArticleList = (state, action) => {
  return state.merge({
    articleList: state.get('articleList').concat(action.list),
    articlePage: action.nextPage
  });
}

export default (state = defaultState, action) => {
  switch(action.type) {
    case constants.CHANGE_HOME_DATA:
      return changeHomeData(state, action);
    case constants.ADD_ARTICLE_LIST:
      return addArticleList(state, action);
    case constants.TOGGLE_SCROLL_TOP:
      return state.set('showScroll', action.show);
    default:
      return state;
  }
};

4.

src
——pages
————home
——————store
————————actionCreators.js

import axios from 'axios';
import * as constants from './constants';
import { fromJS } from 'immutable';


const changeHomeData = (result) => ({
 // ...
});

const addHomeList = (list, nextPage) => ({
  //...
});

export const getHomeInfo = () => {
  // ...
};

export const getMoreList = (page) => {
  //...
};

export const toggleTopShow = (show) => {
  type: constants.TOGGLE_SCROLL_TOP,
  show
};

src
——pages
————home
——————store
————————constants.js

export const TOGGLE_SCROLL_TOP = 'home/TOGGLE_SCROLL_TOP';

8-10 首页性能优化及路由跳转

代码调优:只重新渲染相关组件

src
——pages
————home
——————index.js

import React, { PureComponent } from 'immutable';
class Home extends PureComponent {
  // shouldComponentUpdate() {}
}

路由跳转

src
——pages
————home
——————components
————————List.js

//...
import { Link } from 'react-router-dom';

function List(props) {
  const { list, getMoreList, page } = props;
  return (
    <div>
      {
        list.map((item, index) => {
          return (
            <Link key={index} to='/detail'>
              <ListItem>
               // ...
              </ListItem>
            </Link>
         )
        })
      }
      <LoadMore onClick={() => getMoreList(page)}>更多文字</LoadMore>
    </div>
  );
}

const mapState = (state) => ({
  //...
});

const mapDispatch = (dispatch) => ({
  //...
});

export default connect(mapState, mapDispatch)(List);

src
——common
————header
——————index.js


// ...
<Link to='/'>
  <Logo />
</Link>
// ...

src
——common
————header
——————style.js

export const Logo = styled.div``

You should not use <Link> outside a <Router>

src
——App.js

//...
function App() {
  return (
    <Provider store={store}>
      <GlobalStyle />
      <BrowserRouter>
        <Header />
        <Route path='/' exact component={Home}></Route>
        <Route path='/detail' exact component={Detail}></Route>
      </BrowserRouter>
    </Provider>
  );
}
//...

https://www.jianshu.com/p/4a73276efd55

相关文章

网友评论

      本文标题:React 16.4 开发简书项目[8]

      本文链接:https://www.haomeiwen.com/subject/rldiwctx.html