• React 全栈体系(八)


    第四章 React ajax

    三、案例 – github 用户搜索

    2. 代码实现

    2.3 axios 发送请求
    Search
    /* 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>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    2.4 展示数据
    2.4.1 App
    /* 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>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    2.4.2 Search
    /* 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>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    2.4.3 List
    /* 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>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    2.5 完成案例
    2.5.1 App
    /* 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>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    2.5.2 Search
    /* 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>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    2.5.3 List
    /* 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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    四、消息订阅-发布机制

    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
    /* 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>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    4.2 Search
    /* 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>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    4.3 List
    /* 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>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    五、扩展:Fetch

    1. 文档

    • https://github.github.io/fetch/

    2. 特点

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

    3. 相关 API

    3.1 GET 请求
    fetch(url).then(function(response) {
        return response.json()
      }).then(function(data) {
        console.log(data)
      }).catch(function(e) {
        console.log(e)
      });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    3.2 POST 请求
    fetch(url, {
      method: "POST",
      body: JSON.stringify(data),
    }).then(function(data) {
      console.log(data)
    }).catch(function(e) {
      console.log(e)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4. github 用户搜索代码 - fetch

    Search
    /* 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>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    六、总结

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 相关阅读:
    防抖和节流是什么?防抖和节流的使用场景(附源代码分享)
    动态生成表格完整版(内含解析)
    移动端技术解决方案
    abc 137 Count 1‘s 【经典思维】
    Java中的Map集合
    相交链表+判断环型链表+求环型链表的入口节点
    numpy(np) np 文件存储与读取
    ssm基于web图书租售管理系统的设计与实现毕业设计源码161609
    MTK联发科MT6853和MT6873安卓核心板性能参数对比
    react-router-dom6学习11-如何使用路由监听上
  • 原文地址:https://blog.csdn.net/sgsgkxkx/article/details/132912838