React 从网络请求到列表渲染(附跨域问题的解决)

1,471 阅读3分钟

列表渲染

页面处理的数据较为复杂一些,一般格式为数组和数组对象

数组

// rcc 类组件快捷代码提示
import React, { Component } from "react";

export default class App extends Component {
  // 使用state存储还是普通类属性存储?
  // state修改后DOM刷新
  // 普通属性 存储 不修改
  skills = ["uni-app", "react", "reactNative", "angular", "ionic"];
  // 把数组元素显示在单独的按钮上
  // 分析:
  // 1、数组元素需要一个一个遍历出来,外层包裹一个button标签
  // 2、把拼接好的标签元素,添加一个数组中,在页面上渲染这个数组
  showBtn() {
    // 1.声明一个空数组
    let arr = [];
    // 2.遍历源数据 拼接标签 并添加到新数组
    // item代表数组元素值 index代表数组的下标
    this.skills.forEach((item, index) => {
      // key 标签唯一值 渲染过程中 判断节点的更新
      let tmp = (
        <button style={{ marginLeft: "10px" }} key={index}>
          {item}
        </button>
      );
      arr.push(tmp);
    });
    // 3.返回拼接好的数组
    return arr;
  }
  // 练习:将skills数组内容显示到列表标签中
  // 分析:最外层是ul 每一个元素标签为li标签
  showList() {
    let arr = [];
    this.skills.forEach((item, index) => {
      arr.push(<li key={index}>{item}</li>);
    });
    return arr;
  }
  render() {
    return (
      <div>
        {/* 默认数组元素会挨个渲染到页面上  */}
        {this.skills}
        {/* 调用button数组 */}
        {/* 事件触发的方法不加() */}
        {/* 普通方法调用 需要加() */}
        <br />
        {this.showBtn()}
        {/* 调用显示列表 */}
        <ul>{this.showList()}</ul>
      </div>
    );
  }
}

数组对象

import React, { Component } from "react";

export default class App extends Component {
  banners = [
    {
      title: "联想笔记本",
      url: "http://www.codeboy.com:9999/img/index/banner1.png",
    },
    {
      title: "戴尔笔记本",
      url: "http://www.codeboy.com:9999/img/index/banner2.png",
    },
    {
      title: "皮面笔记本",
      url: "http://www.codeboy.com:9999/img/index/banner3.png",
    },
    {
      title: "网格笔记本",
      url: "http://www.codeboy.com:9999/img/index/banner4.png",
    },
  ];
  showBanners() {
    let arr = [];
    this.banners.forEach((item, index) => {
      let tmp = (
        <div key={index}>
          <img src={item.url} width="200" />
          <div>{item.title}</div>
        </div>
      );
      arr.push(tmp);
    });
    return arr;
  }
  render() {
    return (
      <div>
        {/* 调用显示图片和标题 */}
        {this.showBanners()}
      </div>
    );
  }
}

map方法遍历

map语法 会处理数组的元素直接返回新数组

import React, { Component } from "react";

export default class App extends Component {
  banners = [
    {
      title: "联想笔记本",
      url: "http://www.codeboy.com:9999/img/index/banner1.png",
    },
    {
      title: "戴尔笔记本",
      url: "http://www.codeboy.com:9999/img/index/banner2.png",
    },
    {
      title: "皮面笔记本",
      url: "http://www.codeboy.com:9999/img/index/banner3.png",
    },
    {
      title: "网格笔记本",
      url: "http://www.codeboy.com:9999/img/index/banner4.png",
    },
  ];
  showBanners() {
    let arr = [];
    this.banners.forEach((item, index) => {
      let tmp = (
        <div key={index}>
          <img src={item.url} width="200" />
          <div>{item.title}</div>
        </div>
      );
      arr.push(tmp);
    });
    return arr;
  }
  render() {
    return (
      <div>
        {/* 调用显示图片和标题 */}
        {this.showBanners()}
      </div>
    );
  }
}

数组对象使用map语法

import React, { Component } from "react";

export default class App extends Component {
  banners = [
    {
      title: "联想笔记本",
      url: "http://www.codeboy.com:9999/img/index/banner1.png",
    },
    {
      title: "戴尔笔记本",
      url: "http://www.codeboy.com:9999/img/index/banner2.png",
    },
    {
      title: "皮面笔记本",
      url: "http://www.codeboy.com:9999/img/index/banner3.png",
    },
    {
      title: "网格笔记本",
      url: "http://www.codeboy.com:9999/img/index/banner4.png",
    },
  ];
  // 通过foreach实现
  showBanners1() {
    let arr = [];
    this.banners.forEach((item, index) => {
      let tmp = (
        <div key={index}>
          <img src={item.url} width="200" />
          <div>{item.title}</div>
        </div>
      );
      arr.push(tmp);
    });
    return arr;
  }
  // 通过map实现
  // 注意点
  // 1.外层方法使用箭头函数定义 map里的回调方法也使用箭头函数定义
  // 2.箭头函数 如果没有return关键字语法 就不写{} 箭头函数里面返回值就是一行 用()
  showBanners = () =>
    this.banners.map((item, index) => (
      <div key={index}>
        <img src={item.url} width={200} />
        <div>{item.title}</div>
      </div>
    ));
  render() {
    return (
      <div>
        {/* 调用显示图片和标题 */}
        {this.showBanners()}
      </div>
    );
  }
}

生命周期

组件生命周期 组件开发到结束的整个过程。react提供了组件在各个生命节点的操作方法,称为钩子函数

Vue的组件生命周期:created=>mounted=>updated=>destoryed

componentDidmount 组件挂在时触发 初始化操作和发送网络请求

shouldComponentUpdate 组件将要更新 可以用来控制重绘DOM的时机 这个方法 必须要有一个返回值 bool类型 true 渲染 fasle为不渲染

componentDidUpdate 组件状态更新时触发 监控到状态的变化 如果状态发生改变需要进行特定业务操作,可以写在这里

componentWillUnmount 组件将要销毁时触发 回收资源操作

网络请求

客户端请求服务端接口,需要通过JS代码发送请求。是浏览器XHR对象

不同的框架,对于XHR对象进行封装

JQuery .get().get() .post() $.ajax()

Vue axios

wx wx.request

uni-app uni.request

...............

// rcc 
// 网络请求
import React, { Component } from 'react'

export default class App extends Component {
  componentDidMount(){
    // 发送请求写在这里
    const url= "https://api.apiopen.top/getWangYiNews"
    // get请求
    // res.json() 处理数据为json对象格式
    fetch(url).then(res=>res.json()).then(res=>{
      console.log(res);
    })
  }
  render() {
    return (
      <div>
        
      </div>
    )
  }
}

跨域代理

浏览器端因为同源策略,存在跨域问题。一般开发过程中,使用proxy代理方式解决。

需要安装一个代理插件 http-proxy-middleware

①在项目包根路径安装代理插件

npm i http-proxy-middleware

安装之后在项目包的package.json中查看依赖,是否安装成功

1641803556804

②建立配置文件

配置文件修改后,注意重启项目服务

/src/setupProxy.js

// /src/setupProxy.js 路径和文件名注意写对

const {createProxyMiddleware} = require('http-proxy-middleware');

module.exports = function(app){
  // 插件使用
  // 如果有多个域名需要配置跨域  使用多个app.use()
  app.use(
    // 配置代理相关信息
    createProxyMiddleware("/douyu",{
      target:"https://m.douyu.com",
      changeOrigin:true,
      secure:true,
      pathRewrite:{
        "^/douyu":""
      }
    })
  )
}
// rcc
import React, { Component } from 'react'

export default class App extends Component {
  state = {data:null}
  componentDidMount(){
    this.getData()
  }
  getData(){
    // const url = 'https://m.douyu.com/api/room/list?type=yz'
    // 配合代理 需要修改url地址 添加一个标识信息
    const url = '/douyu/api/room/list?type=yz'
    fetch(url).then(res=>res.json()).then(res=>{
      console.log(res);
      this.setState({data:res.data}) 
    })
  }
  showRooms = ()=>this.state.data.list.map((item,index)=>(
    <div key={index}>
      <img src={item.roomSrc} />
      <div>{item.roomName}</div>
    </div>
  ))
  render() {
    // 判断接口数据未返回时,不渲染  返回空标签
    if(this.state.data == null) return <div></div>;
    return (
      <div>
        {this.showRooms()}
      </div>
    )
  }
}

子元素绑定

// rcc
// ref绑定
/***
 *  子元素绑定: 通过绑定的变量 调用子元素的方法或者属性
 *  Vue中ref概念 通过变量可以获取到组件标签对象
 *  <uni-pop ref="popup"></uni-pop>
 *  调用uni-pop组件的open方法 实现弹出层效果
 *  this.$refs.popup 组件对象
 *  this.$refs.popup.open() 组件对象调用方法
 */
import React, { Component } from 'react'

export default class App extends Component {
  // 方法一:声明变量
  son1 = React.createRef();
  useSon(){
    // 调用子元素的方法
    // 方法一调用
    this.son1.current.show()
    this.son2.show()
  }
  render() {
    return (
      <div>
        {/* 方法一 绑定的变量提前声明*/}
        <Son ref={this.son1}/>
        {/* 方法二 直接绑定不需要提前声明 */}
        {/* JS中如果对象属性不存在会自动声明创建 */}
        {/* el当前组件标签 Son */}
        <Son ref={(el)=>(this.son2=el)}></Son>
        {/* 调用子元素的方法 */}
        <button onClick={this.useSon.bind(this)}>调用子元素</button>
      </div>
    )
  }
}
class Son extends Component{
  num = 5;
  show(){
    alert('我是子组件的show方法')
  }
  render(){
    return <div>我是子组件</div>
  }
}