React 全栈体系(八)

第四章 React ajax

三、案例 -- github 用户搜索

2. 代码实现

2.3 axios 发送请求
javascript 复制代码
/* src/components/Search/index.jsx */
import React, { Component } from "react";
import axios from 'axios'

export default class Search extends Component {

  search = () => {
    //获取用户的输入(连续解构赋值+重命名)
    const { keyWordElement:{value:keyword} } = this
    console.log(keyword);
    //发送网络请求
    axios.get(`https://api.github.com/search/users?q=${keyword}`).then(
      response => {console.log('c', response.data);},
      error => {console.log('d', error);}
    )
  }

  render() {
    return (
      <section className="jumbotron">
        <h3 className="jumbotron-heading">Search Github Users</h3>
        <div>
          <input ref={c => this.keyWordElement = c} type="text" placeholder="enter the name you search" />
          &nbsp;
          <button onClick={this.search}>Search</button>
        </div>
      </section>
    );
  }
}
2.4 展示数据
2.4.1 App
javascript 复制代码
/* src/App.jsx */
import React, { Component } from "react";
import Search from "./components/Search";
import List from "./components/List";

export default class App extends Component {

  state = {users:[]} //初始化状态,users初始值为数组

  saveUsers = (users)=>{
    this.setState({users})
  }
  render() {
    const {users} = this.state
    return (
      <div className="container">
        <Search saveUsers={this.saveUsers}/>
        <List users={users}/>
      </div>
    );
  }
}
javascript 复制代码
/* src/components/Search/index.jsx */
import React, { Component } from "react";
import axios from 'axios'

export default class Search extends Component {

  search = () => {
    //获取用户的输入(连续解构赋值+重命名)
    const { keyWordElement:{value:keyword} } = this
    //发送网络请求
    axios.get(`https://api.github.com/search/users?q=${keyword}`).then(
      response => {
        this.props.saveUsers(response.data.items)
      },
      error => {console.log('d', error);}
    )
  }

  render() {
    return (
      <section className="jumbotron">
        <h3 className="jumbotron-heading">Search Github Users</h3>
        <div>
          <input ref={c => this.keyWordElement = c} type="text" placeholder="enter the name you search" />
          &nbsp;
          <button onClick={this.search}>Search</button>
        </div>
      </section>
    );
  }
}
2.4.3 List
javascript 复制代码
/* src/components/List/index.jsx */
import React, { Component } from "react";
import "./index.css";

export default class List extends Component {
  render() {
    return (
      <div className="row">
        {this.props.users.map((userObj) => {
          return (
            <div key={userObj.id} className="card">
              <a rel="noreferrer" href={userObj.html_url} target="_blank">
                <img
                  alt="head_portrait"
                  src={userObj.avatar_url}
                  style={{ width: "100px" }}
                />
              </a>
              <p className="card-text">{userObj.login}</p>
            </div>
          );
        })}
      </div>
    );
  }
}
2.5 完成案例
2.5.1 App
javascript 复制代码
/* src/App.jsx */
import React, { Component } from "react";
import Search from "./components/Search";
import List from "./components/List";

export default class App extends Component {
  state = {
    //初始化状态
    users: [], //users初始值为数组
    isFirst: true, //是否为第一次打开页面
    isLoading: false, //标识是否处于加载中
    err: "", //存储请求相关的错误信息
  };

  //更新App的state
  updateAppState = (stateObj) => {
    this.setState(stateObj);
  };

  render() {
    const { users } = this.state;
    return (
      <div className="container">
        <Search updateAppState={this.updateAppState} />
        <List {...this.state} />
      </div>
    );
  }
}
javascript 复制代码
/* src/components/Search/index.jsx */
import React, { Component } from "react";
import axios from "axios";

export default class Search extends Component {
  search = () => {
    //获取用户的输入(连续解构赋值+重命名)
    const {
      keyWordElement: { value: keyword },
    } = this;
    //发送请求前通知App更新状态
    this.props.updateAppState({ isFirst: false, isLoading: true });
    //发送网络请求
    axios.get(`https://api.github.com/search/users?q=${keyword}`).then(
      (response) => {
        //请求成功后通知App更新状态
        this.props.updateAppState({
          isLoading: false,
          users: response.data.items,
        });
      },
      (error) => {
        //请求失败后通知App更新状态
        this.props.updateAppState({ isLoading: false, err: error.message });
      }
    );
  };

  render() {
    return (
      <section className="jumbotron">
        <h3 className="jumbotron-heading">Search Github Users</h3>
        <div>
          <input
            ref={(c) => (this.keyWordElement = c)}
            type="text"
            placeholder="enter the name you search"
          />
          &nbsp;
          <button onClick={this.search}>Search</button>
        </div>
      </section>
    );
  }
}
2.5.3 List
javascript 复制代码
/* src/components/List/index.jsx */
import React, { Component } from "react";
import "./index.css";

export default class List extends Component {
  render() {
    const { users, isFirst, isLoading, err } = this.props;
    return (
      <div className="row">
        {isFirst ? (
          <h2>Welcome, enter a keyword and then click search!</h2>
        ) : isLoading ? (
          <h2>Loading......</h2>
        ) : err ? (
          <h2 style={{ color: "red" }}>{err}</h2>
        ) : (
          users.map((userObj) => {
            return (
              <div key={userObj.id} className="card">
                <a rel="noreferrer" href={userObj.html_url} target="_blank">
                  <img
                    alt="head_portrait"
                    src={userObj.avatar_url}
                    style={{ width: "100px" }}
                  />
                </a>
                <p className="card-text">{userObj.login}</p>
              </div>
            );
          })
        )}
      </div>
    );
  }
}

四、消息订阅-发布机制

1. 工具库

  • PubSubJS

2. 下载

  • npm install pubsub-js --save

3. 使用

  • import PubSub from 'pubsub-js' //引入
  • PubSub.subscribe('delete', function(data){ }); //订阅
  • PubSub.publish('delete', data) //发布消息

4. github 用户搜索代码重构

4.1 App
javascript 复制代码
/* src/App.jsx */
import React, { Component } from "react";
import Search from "./components/Search";
import List from "./components/List";

export default class App extends Component {
  render() {
    return (
      <div className="container">
        <Search />
        <List />
      </div>
    );
  }
}
javascript 复制代码
/* src/components/Search/index.jsx */
import React, { Component } from "react";
import PubSub from "pubsub-js";
import axios from "axios";

export default class Search extends Component {
  search = () => {
    //获取用户的输入(连续解构赋值+重命名)
    const {
      keyWordElement: { value: keyword },
    } = this;
    //发送请求前通知List更新状态
    PubSub.publish("alex", { isFirst: false, isLoading: true });
    //发送网络请求
    axios.get(`https://api.github.com/search/users?q=${keyword}`).then(
      (response) => {
        //请求成功后通知List更新状态
        PubSub.publish("alex", {
          isLoading: false,
          users: response.data.items,
        });
      },
      (error) => {
        //请求失败后通知List更新状态
        PubSub.publish("alex", { isLoading: false, err: error.message });
      }
    );
  };

  render() {
    return (
      <section className="jumbotron">
        <h3 className="jumbotron-heading">Search Github Users</h3>
        <div>
          <input
            ref={(c) => (this.keyWordElement = c)}
            type="text"
            placeholder="enter the name you search"
          />
          &nbsp;
          <button onClick={this.search}>Search</button>
        </div>
      </section>
    );
  }
}
4.3 List
javascript 复制代码
/* src/components/List/index.jsx */
import React, { Component } from "react";
import PubSub from "pubsub-js";
import "./index.css";

export default class List extends Component {
  state = {
    //初始化状态
    users: [], //users初始值为数组
    isFirst: true, //是否为第一次打开页面
    isLoading: false, //标识是否处于加载中
    err: "", //存储请求相关的错误信息
  };

  componentDidMount() {
    this.token = PubSub.subscribe("alex", (_, stateObj) => {
      this.setState(stateObj);
    });
  }

  componentWillUnmount() {
    PubSub.unsubscribe(this.token);
  }

  render() {
    const { users, isFirst, isLoading, err } = this.state;
    return (
      <div className="row">
        {isFirst ? (
          <h2>Welcome, enter a keyword and then click search!</h2>
        ) : isLoading ? (
          <h2>Loading......</h2>
        ) : err ? (
          <h2 style={{ color: "red" }}>{err}</h2>
        ) : (
          users.map((userObj) => {
            return (
              <div key={userObj.id} className="card">
                <a rel="noreferrer" href={userObj.html_url} target="_blank">
                  <img
                    alt="head_portrait"
                    src={userObj.avatar_url}
                    style={{ width: "100px" }}
                  />
                </a>
                <p className="card-text">{userObj.login}</p>
              </div>
            );
          })
        )}
      </div>
    );
  }
}

五、扩展:Fetch

1. 文档

2. 特点

  • fetch: 原生函数,不再使用 XmlHttpRequest 对象提交 ajax 请求
  • 老版本浏览器可能不支持

3. 相关 API

3.1 GET 请求
javascript 复制代码
fetch(url).then(function(response) {
    return response.json()
  }).then(function(data) {
    console.log(data)
  }).catch(function(e) {
    console.log(e)
  });
3.2 POST 请求
javascript 复制代码
fetch(url, {
  method: "POST",
  body: JSON.stringify(data),
}).then(function(data) {
  console.log(data)
}).catch(function(e) {
  console.log(e)
})

4. github 用户搜索代码 - fetch

javascript 复制代码
/* src/components/Search/index.jsx */
import React, { Component } from "react";
import PubSub from "pubsub-js";

export default class Search extends Component {
  search = async()=>{
		//获取用户的输入(连续解构赋值+重命名)
		const {keyWordElement:{value:keyWord}} = this
		//发送请求前通知List更新状态
		PubSub.publish('alex',{isFirst:false,isLoading:true})
		//#region 发送网络请求---使用axios发送
		/* axios.get(`https://api.github.com/search/users?q=${keyWord}`).then(
			response => {
				//请求成功后通知List更新状态
				PubSub.publish('alex',{isLoading:false,users:response.data.items})
			},
			error => {
				//请求失败后通知App更新状态
				PubSub.publish('alex',{isLoading:false,err:error.message})
			}
		) */
		//#endregion

		//发送网络请求---使用fetch发送(未优化)
		/* fetch(`https://api.github.com/search/users?q=${keyWord}`).then(
			response => {
				console.log('联系服务器成功了');
				return response.json()
			},
			error => {
				console.log('联系服务器失败了',error);
				return new Promise(()=>{})
			}
		).then(
			response => {console.log('获取数据成功了',response);},
			error => {console.log('获取数据失败了',error);}
		) */

		//发送网络请求---使用fetch发送(优化)
		try {
			const response= await fetch(`https://api.github.com/search/users?q=${keyWord}`)
			const data = await response.json()
			PubSub.publish('alex',{isLoading:false,users:data.items})
		} catch (error) {
			PubSub.publish('alex',{isLoading:false,err:error.message})
		}
	}

  render() {
    return (
      <section className="jumbotron">
        <h3 className="jumbotron-heading">Search Github Users</h3>
        <div>
          <input
            ref={(c) => (this.keyWordElement = c)}
            type="text"
            placeholder="enter the name you search"
          />
          &nbsp;
          <button onClick={this.search}>Search</button>
        </div>
      </section>
    );
  }
}

六、总结

bash 复制代码
1.设计状态时要考虑全面,例如带有网络请求的组件,要考虑请求失败怎么办。
2.ES6小知识点:解构赋值+重命名
	let obj = {a:{b:1}}
	const {a} = obj; //传统解构赋值
	const {a:{b}} = obj; //连续解构赋值
	const {a:{b:value}} = obj; //连续解构赋值+重命名
3.消息订阅与发布机制
	1.先订阅,再发布(理解:有一种隔空对话的感觉)
	2.适用于任意组件间通信
	3.要在组件的componentWillUnmount中取消订阅
4.fetch发送请求(关注分离的设计思想)
	try {
		const response= await fetch(`/api1/search/users2?q=${keyWord}`)
		const data = await response.json()
		console.log(data);
	} catch (error) {
		console.log('请求出错',error);
	}
相关推荐
左耳咚1 分钟前
如何解析 zip 文件
前端·javascript·面试
程序员小寒11 分钟前
前端高频面试题之Vue(初、中级篇)
前端·javascript·vue.js
陈辛chenxin18 分钟前
软件测试大赛Web测试赛道工程化ai提示词大全
前端·可用性测试·测试覆盖率
沿着路走到底20 分钟前
python 判断与循环
java·前端·python
Code知行合壹22 分钟前
AJAX和Promise
前端·ajax
大菠萝学姐32 分钟前
基于springboot的旅游攻略网站设计与实现
前端·javascript·vue.js·spring boot·后端·spring·旅游
心随雨下44 分钟前
TypeScript中extends与implements的区别
前端·javascript·typescript
摇滚侠1 小时前
Vue 项目实战《尚医通》,底部组件拆分与静态搭建,笔记05
前端·vue.js·笔记·vue
双向331 小时前
CANN训练营实战指南:从算子分析到核函数定义的完整开发流程
前端
caleb_5201 小时前
vue cli的介绍
前端·javascript·vue.js