zoukankan      html  css  js  c++  java
  • React学习(四)----- 基于React脚手架的React应用

    1、React脚手架

    • 什么是脚手架???

    用来帮助程序员快速创建一个基于React库的模板项目

        1) 包含了所有需要的配置(语法检查、jsx编译、devServer…)

        2) 下载好了所有相关的依赖

        3) 可以直接运行一个简单效果

        4) 项目的整体技术架构为:  react + webpack + es6 + eslint

        5) 使用脚手架开发项目的特点: 模块化, 组件化, 工程化

    • 脚手架的安装
      cnpm  install  create-react-app  -g
    • 创建项目
      1、创建项目
           create-react-app hello-react
      
      2、进入项目目录
           cd hello-react
      
      3、启动项目
           npm start
    • React脚手架项目结构
      • public ----- 静态资源文件夹
        • favicon.ico ----- 网站页签图标
        • index.html ----- 主页面
          <!DOCTYPE html>
          <html lang="en">
            <head>
              <meta charset="utf-8" />
              <!-- %PUBLIC_URL%代表public文件夹的路径 相当于./favicon.ico -->
              <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
              <!-- 开启理想视口,用于做移动端网页的适配 -->
              <meta name="viewport" content="width=device-width, initial-scale=1" />
              <!-- 用于配置浏览器页签 + 地址栏的颜色 ,只针对安卓手机浏览器(兼容性不好,有些机型无效果),不支持ios-->
              <meta name="theme-color" content="#000000" />
              <meta
                name="description"
                content="Web site created using create-react-app"
              />
              <!-- 只支持ios手机:用于指定网页添加到手机主屏幕后的图标 -->
              <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
              <!-- 应用加壳的配置文件 -->
              <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
              <title>React App</title>
            </head>
            <body>
              <!-- 当浏览器不支持js时展示的提示信息 -->
              <noscript>You need to enable JavaScript to run this app.</noscript>
              <!-- 容器,挂载虚拟DOM的地方,也就是ReactDOM.render方法的第二个参数 -->
              <div id="root"></div>
            </body>
          </html>
        • robots.txt ----- 爬虫协议文件
      • src ----- 源码文件夹
        • App.css ----- App组件的样式
        • App.js ----- App组件
        • App.test.js ----- 用于给App做测试
        • index.css ----- 样式
        • index.js ----- 入口文件:React.StrictMode 用于检查App和App的子组件的写法是否合理
        • logo.svg ----- logo图
        • reportWebVitals.js ----- 页面性能分析文件(需要web-vitals库的支持)
        • setupTests.js ----- 组件单元测试的文件(主要jest-dom库的支持)

    2、一个简单的Hello组件

    • vscode中react插件的安装
      ES7 React/Redux/GraphQL/React-Native snippets
    • 样式的模块化
      • 组件的文件目录

                         

      • 将组件的css文件命名为:index.module.css,在组件jsx中的引入方式为用一个变量接收,并且定义的时候使用差值表达式的方式定义,这样不会造成样式污染
        import { Component } from "react";
        import hello from './index.module.css'
        
        export default class Hello extends Component {
          render() {
            return <h1 className={hello.title}>Hello,React!!!!</h1>;
          }
        }

        不然结果就是:同名的class标签只会使用后引入的css文件

                       

    •  功能界面的组件化编码流程
      1. 拆分组件: 拆分界面,抽取组件
      2. 实现静态组件: 使用组件实现静态页面效果
      3. 实现动态组件
          3.1 动态显示初始化数据
              3.1.1 数据类型
              3.1.2 数据名称
              3.1.3 保存在哪个组件?
          3.2 交互(从绑定事件监听开始)

    3、组件的组合使用(TodoList)

    • 效果图

             

    • 知识点
      • 步骤

                       

      • 生成唯一的id值得库
        cnpm i uuid/nanoid -D//uuid库比较大,建议选择nanoid
      • 非父子组件之间的传值
        1、子传父、父传子  即Header传给App,App传给List
            (1)子传父
                    子组件在父组件当做标签使用
                    1) 子组件this.props.sendData(event.target.value)
                    2) 父组件中的子组件绑定数据
        <Header sendData={this.receiveData} />
                    3) 父组件中的方法
        receiveData = (data) => {
          console.log(data);
        };
            (2)父传子
                    子组件在父组件当做标签使用
                    1) 父组件中的子组件绑定数据
        <Header {...this.state}} />
                    2) 在子组件的render方法中使用this.props进行接收
      • checkbox的相关问题
        1、checked属性必须与onChange事件一起使用;
        2、defaultChecked属性只有第一次会生效,后效修改将无效;

    4、React Ajax

    • 为什么要引入Ajax???
      1.React本身只关注于界面, 并不包含发送ajax请求的代码
      2.前端应用需要通过ajax请求与后台进行交互(json数据)
      3.react应用中需要集成第三方ajax库(或自己封装)
    • 常用的Ajax请求库
      1.jQuery: 比较重, 直接操作DOM,会有回调函数地域的问题,如果需要另外引入不建议使用
      2.axios: 轻量级, 建议使用
         1)封装XmlHttpRequest对象的ajax
         2)promise风格
         3)可以用在浏览器端和node服务器端
    • 脚手架配置代理(客户端解决,服务器的话使用cors)
      • 跨域原因
        http://localhost:3000 -----> http://localhost:5000/students
        原因:由于Ajax引擎的限制,请求可以从3000发送到5000端口,但是响应的时候被引擎拦截,这个时候我们可以配置代理
            (设置一个中间人服务器,也在3000端口运行,而中间服务器没有ajax引擎的影响,且服务器之间无同源策略的影响,可以正常接收响应,接收到响应数据后,由于端口都是
        3000,客户端直接收到数据)
        本地3000端口运行这一个脚手架,一个服务器,name脚手架和服务器由于协议、域名、端口号完全一致,所以不会产生跨域,而本地代理的服务器与访问服务器之间不受同源策略的影响
        因此也可以正常的接收到数据,代理服务器收到数据后再返回给客户端,因此解决跨域问题!!!
      • 第一种方式:代理一个服务器的情况下,多个不允许这么配置
        • 步骤
          1、修改package.json
          "proxy": "http://localhost:5000"
          2、重启
          npm start 
          3、修改请求接口
          http://localhost:5000/students -----> http://localhost:3000/students
        • 说明
          1. 优点:配置简单,前端请求资源时可以不加任何前缀。
          2. 缺点:不能配置多个代理。
          3. 工作方式:上述方式配置代理,当请求了3000不存在的资源时,那么该请求会转发给5000 (优先匹配前端资源)
      • 第二种方式:代理多个服务器
        • 步骤
          1. 第一步:创建代理配置文件
             在src下创建配置文件:src/setupProxy.js
          2. 编写setupProxy.js配置具体代理规则:
             // 使用commonjs的语法,引入一个内置插件  无需安装
             const proxy = require('http-proxy-middleware')
             
             module.exports = function(app) {
               app.use(
                 proxy('/api1', {  //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)
                   target: 'http://localhost:5000', //配置转发目标地址(能返回数据的服务器地址)
                   changeOrigin: true, //控制服务器接收到的请求头中host字段的值
                   /*
                       changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
                       changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
                       changeOrigin默认值为false,但我们一般将changeOrigin值设为true
                   */
                   pathRewrite: {'^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)  重写请求路径
                 }),
                 proxy('/api2', { 
                   target: 'http://localhost:5001',
                   changeOrigin: true,
                   pathRewrite: {'^/api2': ''}
                 })
               )
             }
        • 说明
          1. 优点:可以配置多个代理,可以灵活的控制请求是否走代理。
          2. 缺点:配置繁琐,前端请求资源时必须加前缀。
    • github搜索案例
      • 效果图

                         

      • 知识点
        • 连续解构赋值
           const obj = {a:{b:{c:1}}}
           console.log(obj.a.b.c) //1
           const { a: { b: { c } } } = obj
           console.log(c) //1

    5、发布-订阅机制(适用于任意组件的通信)

    • 安装
      cnpm i pubsub-js -S
    • 使用:Search组件传递给-----List组件(兄弟组件之间的传值)
      • List组件订阅消息
        import PubSub from 'pubsub-js'
        
        componentDidMount(){
          // 订阅消息
          this.token = PubSub.subscribe("updateAppState",(msg,data)=>{
            console.log("list")
            console.log(msg,data)//msg是updateAppState,即事件的名称,data是发布的消息
            this.setState(data) 
          }) 
        } 
        //取消订阅
        componentWillUnmount(){
          PubSub.unsubscribe(this.token) 
        }
      • Search组件发布消息
        import PubSub from 'pubsub-js'
        
        PubSub.publish('updateAppState',{ isFirst: false,isLoading:true })

     6、前后端交互的方式

    • jquery/axios
      • 特点
        axios是一个基于Promise,用于浏览器和 nodejs 的 HTTP 客户端,它本身具有以下特征:
            1)从浏览器中创建 XMLHttpRequest
            2)从 node.js 发出 http 请求
            3)支持 Promise API
            4)拦截请求和响应
            5)转换请求和响应数据
            6)自动转换JSON数据, 
            7)客户端支持防止CSRF/XSRF
      • 示例
        import axios from 'axios'
        
        axios.get(`http://localhost:3000/api/search/users?q=${inputValue}`).then((res) => {
          // 请求成功后通知App更新状态
          updateAppState({isLoading:false,users:res.data.items})
        }).catch(err => {
          updateAppState({isLoading:false,err:err.message})
        })
    • fetch ----- 无需安装,浏览器内置
      • 特点
        fetch:返回的是一个未处理的方法集合,我们可以通过这些方法得到我们想要的数据类型。如果我们想要json格式,就执行res.json(),如果我们想要字符串就res.text()
            1)关注分离,没有将输入、输出和用事件来跟踪的状态混杂在一个对象里
            2)更加底层,提供的API丰富(request, response)
            3)脱离了XHR,是ES规范里新的实现方式
            4)fetch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理
            5)fetch默认不会带cookie,需要添加配置项
            6)fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了量的浪费
            7)fetch没有办法原生监测请求的进度,而XHR可以
      • 请求格式
        默认是get请求,如果需要向后端发送数据,则直接在地址后面做拼接
        当请求post方式时:
        fetch(url,
            {
                  method:"post",
                  body: JSON.stringify(obj),
                  headers : {//必须要写
                       "Content-type" : "application/json";
                       "credentials": 'include'//携带cookie进行提交
                  }
           }).then((res)=>res.json()).then((data)=>{})
      • 示例:默认为get请求
          fetch(`http://localhost:3000/api/search/users?q=${inputValue}`)
              .then(
                  (res) => {
                      console.log('联系服务器成功了', res)//是一个综合各种方法的对象,并不是请求的数据
                      return res.json()
                  },
                  (error) => {
                    console.log('联系服务器失败了', error)
                    return new Promise(()=>{})//为了防止断网走了上一行后,接着走下一个then中的第一个回调,加上只走上面一行
                })
              .then(
                (res) => {
                  console.log("获取数据成功了",res)
                },
                (error) => {
                 console.log('获取数据失败了',error)
                })
      • 简化代码后
        fetch(`http://localhost:3000/api/search/users?q=${inputValue}`)
              .then(
                  (res) => {
                      console.log('联系服务器成功了', res)//是一个综合各种方法的对象,并不是请求的数据
                      return res.json()
                  }
              )
              .then(
                (res) => {
                  console.log("获取数据成功了",res)
                }
            ).catch(
              (error) => {
                 console.log('请求出错',error)
              }
            )
      • 使用async和await
        try {
             let response = await fetch(`http://localhost:3000/api/search/users?q=${inputValue}`)
             let result = await response.json();
             console.log(result)
         } catch (e) {
             console.log(e)
         }

    7、其他问题

         暂无

     
    北栀女孩儿
  • 相关阅读:
    通过filebeat收集并通过elsaticsearch的pipeline功能解析nginx访问日志
    markdown blog Typora+minio+upic图床改造
    spark 使用shc 访问hbase超时问题解决办法
    定制logstash-output-kafka 添加额外事务参数
    《机器学习十讲》第八讲总结
    寒假学习日报(二十四)
    《机器学习十讲》第七讲总结
    寒假学习日报(二十三)
    《机器学习十讲》第六讲总结
    寒假学习日报(二十二)
  • 原文地址:https://www.cnblogs.com/wxh0929/p/15213730.html
Copyright © 2011-2022 走看看