likes
comments
collection
share

(12)首页开发——④ AJAX 获取首页数据 | React.js 项目实战:PC 端“简书”开发

作者站长头像
站长
· 阅读数 2
转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥“前端一万小时”两大明星专栏——“从零基础到轻松就业”、“前端面试刷题”,已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。

1 mock “首页”数据

在 AJAX 请求数据前,我们得自己 mock 一些数据辅助我们开发。

1️⃣在项目的 public 目录下 api 文件夹中新增一个 homeData.json 文件: (12)首页开发——④ AJAX 获取首页数据 | React.js 项目实战:PC 端“简书”开发

2️⃣编写 mock 数据 homeData.json 中的内容: 前置知识:《JavaScript 基础——JS 提供的对象:⑤ JSON》

{
	"success": true,
  
  "data": {
    "labelList": [{
      "id": 1,
      "title": "简书电影",
      "imgUrl": "https://qdywxs.github.io/jianshu-images/label01.jpg"
    },{
      "id": 2,
      "title": "故事",
      "imgUrl": "https://qdywxs.github.io/jianshu-images/label02.jpg"
    },{
      "id": 3,
      "title": "手绘",
      "imgUrl": "https://qdywxs.github.io/jianshu-images/label03.jpg"
    },{
      "id": 4,
      "title": "历史",
      "imgUrl": "https://qdywxs.github.io/jianshu-images/label04.jpg"
    },{
      "id": 5,
      "title": "人文社科",
      "imgUrl": "https://qdywxs.github.io/jianshu-images/label05.jpg"
    },{
      "id": 6,
      "title": "摄影",
      "imgUrl": "https://qdywxs.github.io/jianshu-images/label06.jpg"
    },{
      "id": 7,
      "title": "自然科普",
      "imgUrl": "https://qdywxs.github.io/jianshu-images/label07.jpg"
    }],

    "articleList": [{
      "id": 1,
      "title": "评“超时空同居”浅议爱情电影和奇幻元素的嫁接",
      "desc": "这部电影充分照顾到了八零后的情怀,九零后的笑点,零零后嘛,那就是奇幻爱情吧。奇幻爱情喜剧,三种元素都有,但哪种都不出彩,相对来说喜剧元素稍微强一…",
      "imgUrl": "https://qdywxs.github.io/jianshu-images/article-img01.jpg",
      "author": "苇筱",
      "discuss": 31,
      "love": 21,
      "money": 1
    },{
      "id": 2,
      "title": "生活随记八则",
      "desc": "1 不再困惑也不再迷茫,头脑中的构想在现实生活中并驾齐驱地向前推进,虽然困难重重但能够想方设法加以克服。前景广阔而美好,只是有一丝淡淡的凄凉,也…",
      "imgUrl": "https://qdywxs.github.io/jianshu-images/article-img02.jpeg",
      "author": "Jobs",
      "discuss": 31,
      "love": 90,
      "money": 8
    },{
      "id": 3,
      "title": "“前端一万小时”又惊艳了我一把",
      "desc": "Hey guys, 我正在这个平台分发“前端一万小时”这个专栏的一系列文章。这个专栏我已经完成了“从零基础到就业”的相关文章。“从零基础到就业”包含 150+ 篇干货文章,300+ 道经典笔试、面试题。如果你对本系列文章感兴趣,欢迎关注 「公众号:前端一万小时」,并点击菜单栏“全部文章”来加入我们的“一万小时计划”!祝顺利,祝成功^^……",
      "imgUrl": "https://qdywxs.github.io/jianshu-images/article-img03.jpg",
      "author": "Oli",
      "discuss": "9k+",
      "love": "10k+",
      "money": "100000k+"
    }],

    "panelsList": [{
      "id": 1,
      "imgUrl": "https://qdywxs.github.io/jianshu-images/panel01.png"
    },{
      "id": 2,
      "imgUrl": "https://qdywxs.github.io/jianshu-images/panel02.png"
    },{
      "id": 3,
      "imgUrl": "https://qdywxs.github.io/jianshu-images/panel03.png"
    },{
      "id": 4,
      "imgUrl": "https://qdywxs.github.io/jianshu-images/panel04.png"
    },{
      "id": 5,
      "imgUrl": "https://qdywxs.github.io/jianshu-images/panel05.png"
    }]
  }
}

3️⃣既然有了 mock 的数据,我们就可以将 home 目录下 store 中的 reducer.js 里写死的“数据”去除掉了:

import {fromJS} from "immutable"; 

const defaultState = fromJS({
  
  // ❗️去除里边写死的“数据”,留下三个“空数组”!
  labelList: [],
  
  articleList: [],
  
  panelsList: []
  
})

export default (state=defaultState, action) => {  
  
  return state;
}

返回页面查看(页面数据都没有了): (12)首页开发——④ AJAX 获取首页数据 | React.js 项目实战:PC 端“简书”开发

2 异步获取并显示数据

在上边图片中可以看到,页面基本上什么数据都没有了。但也正符合正常的逻辑——首页的“数据”肯定不是写死在页面上的,作为“首页”的展示“数据”,它会在“首页组件”挂载完成时,去异步获取并显示“数据”。

故,这里就涉及到了“改变数据”的流程!改变什么“数据”呢——将本来的“空数组”,通过异步获取到的“数据”填满。

4️⃣打开 home 目录下的 index.js 文件:

import React, {Component} from "react";

import Content from "./components/Content";
import Label from "./components/Label";
import Panels from "./components/Panels";
import Download from "./components/Download";

import {
  Section,
  Aside,
  Main,
  ToTop
  
} from "./style.js";

/*
❗️❗️❗️4️⃣-①:从 react-redux 中引入 connect 方法(它也是 React-redux 的核心 API 之一),
connect 的作用很明确——就是“连接”的意思!
 */
import { connect } from "react-redux";


import {actionCreators} from "./store"; // ❗️引入 actionCreators!


class Home extends Component {
  render() {
    return( 
      <div>
        <Section className="layout clearfix"> 
          <Aside>
            <Panels />
            <Download />
          </Aside>
        
          <Main>
            <img className="banner-img" src="https://qdywxs.github.io/jianshu-images/carousel01.jpg" alt="" />
            
            <Label />
            <Content />
          </Main>
        </Section>
        
        
        <ToTop>  
          <span className="up">^</span>
          <span className="tooltip">回到顶部</span>
        </ToTop>
      </div>
    )
  }

  componentDidMount() { // 5️⃣当组件挂载完毕,就去请求“数据”;
    // 5️⃣-①:这里应该怎么去请求“数据”呢?
    
    /*
    ❗️5️⃣-③:因此可以通过 this.props.changeHomeData 来调用 store 中
    的 changeHomeData;
     */
    this.props.changeHomeData();
  }
  
}


/*
❗️❗️❗️4️⃣-⑤:接下来,我们定义哪些“用户的操作”
应该当作 action,并传给 store;
 */
const mapDispatchToProps = (dispatch) => { /*
																					 4️⃣-⑥:把 store 里的“dispatch 方法”
                                           作为“参数”传递给 mapDispatchToProps;
                                            */
  return {
    changeHomeData() { /*
          						 5️⃣-②:在这里定义 changeHomeData 会被当作 action
                       传给 store;
                        */
    
      /*
      5️⃣-④:Redux-thunk 中,“异步”代码我们是放在 action 中进行。
      这里我们仅作方法的“调用”;
       */
      const action = actionCreators.getHomeInfo();
  
      dispatch(action)
    
    },
  }
}




/*
❗️❗️❗️4️⃣-②:之前我们直接导出的是 Home,可用了 React-redux 后,就不能这样写了!
export default Home;
 */

/*
4️⃣-③:取而代之,我们是导出 connect 方法(
❗️注意看我们给 connect 方法传递了哪些参数!);
 */
export default connect(null, mapDispatchToProps)(Home); /*
																				4️⃣-④:我们一共要给 connect 传递 3 个参数!
                                        Home 表示:connect 会让“Home 组件”和 store
                                        进行“连接”;
                                        
                                        null 表示:这里还会接收一个名叫 
                                        mapStateToProps 的参数,由于这里不需要去获取
                                        “数据”,故用 null 来占位。
                                        
                                        mapDispatchToProps 表示:我们把 store 的 
                                        dispatch 方法“挂载”到 Home 组件的 props 上。
                                        即,我们可以定义哪些“用户的操作”应该当作 action,
                                        并传给 store!
                                        								 */

5️⃣-⑤:打开 home 目录下 store 中的 actionCreators.js 文件,定义这个 action;

// 5️⃣-⑦:引入 axios 模块;
import axios from "axios";

// 5️⃣-⑥:在 action 中添加 AJAX“异步”代码;
export const getHomeInfo = () => {
  
  // 5️⃣-⑧:编写“异步”函数;
  return(dispatch) => {
    axios.get("/api/homeData.json")
      .then((res) => {
        const result = res.data.data;
      
      })
      .catch(() => {alert("error")})
  }
}

返回页面,查看“数据”是否成功获取到(已成功获取): (12)首页开发——④ AJAX 获取首页数据 | React.js 项目实战:PC 端“简书”开发

6️⃣既然“数据”已成功获取,接下来就用 AJAX 获取到的数据替换初始的“空数组”。又是“修改数据”的套路,那我们继续走 Redux 的工作流程:

6️⃣-①:打开 home 目录下 store 中的 actionTypes.js 文件;

export const INIT_HOME_DATA = "init_home_data"; // ❗️定义好常量~

6️⃣-②:返回 home 目录下 store 中的 actionCreators.js 文件;

import axios from "axios";

// 6️⃣-③:先引入“常量”;
import {INIT_HOME_DATA} from "./actionTypes";


// 6️⃣-⑦:引入 fromJS 方法;
import {fromJS} from "immutable";


// 6️⃣-⑤:在这里定义 action;
const initHomeData = (result) => ({
  type: INIT_HOME_DATA, 
  
  /*
  ❗️❗️❗️6️⃣-⑥:这里请一定注意,这里的“数据”是从“接口”获取到的“数组”对象,
  它是一个“JS 对象”。
  但在上边的第“3️⃣”步中,“数据项”被 fromJS 修改成了“immutable 对象”,
  因此,这里也应该将 result 转换为“immutable 对象”!
   */
  
  // 6️⃣-⑧:将 result 转化为 immutable 对象;
  labelList: fromJS(result.labelList),
  articleList: fromJS(result.articleList),
  panelsList: fromJS(result.panelsList)
});

export const getHomeInfo = () => {
  return(dispatch) => {
    axios.get("/api/homeData.json")
      .then((res) => {
        const result = res.data.data;
        console.log(result);
      
        // 6️⃣-④:获取到数据后,需要去替换初始的空数组;
        const action = initHomeData(result);
      
        dispatch(action); // ❗️6️⃣-⑨:将这个 action 发送给 reducer!
      })
      .catch(() => {alert("error")})
  }
}

7️⃣打开 home 目录下 store 中的 reducer.js 文件:

import {fromJS} from "immutable"; 

// 7️⃣-①:先引入“常量”;
import {INIT_HOME_DATA} from "./actionTypes";

const defaultState = fromJS({
  labelList: [],
  
  articleList: [],
  
  panelsList: []
  
})

export default (state=defaultState, action) => {  
  // 7️⃣-②:编写替换“数据”的逻辑;
  if(action.type === INIT_HOME_DATA) {
  	return state.merge({ // ❗️注意 merge 的使用!
      labelList: action.labelList,
      articleList: action.articleList,
      panelsList: action.panelsList
    })
  }
  
  return state;
}

返回页面查看效果(异步获取到的“数据”正常显示出来了): (12)首页开发——④ AJAX 获取首页数据 | React.js 项目实战:PC 端“简书”开发

下篇,我们来专门实现“加载更多”这个功能,再次走“改变数据”的流程,熟能生巧!

祝好,qdywxs ♥ you!