React全家桶

React简介

1. 是什么?

    是将数据渲染为HTML视图的开源JavaScript库。

2. 谁开发的?

    是由Facebook开发,且开源。
    起初由Facebook的软件工程师Jordan Walke创建。
    于2011年部署于Facebook的newsfeed。
    随后在2012年部署于Instagram。
    2013年5月宣布开源。

3. 为什么要学?

    1. 原生的JavaScript操作DOM繁琐,效率低(`DOM-API操作UI`)
    2. 使用JavaScript直接操作DOM,浏览器会进行大量的`重绘重排`。
    3. 原生JavaScript没有`组件化`的编码方案,代码复用率低。

4. React的特点?

    1. 采用`组件化`模式,`声明式编码`,提高开发效率及组件复用率。
    2. 在React Native(用熟悉的js编写安卓应用)中可以使用React语法进行`移动端开发`。
    3. 使用`虚拟DOM`  +  优秀的`Diffing算法`,尽量减少于真实DOM的交互。(原生js和jq都是操作的真实的DOM)

5. 学习React之前你要掌握的JavaScript基础知识

    1. 判断this的指向
    2. class(类)
    3. ES6语法规范
    4. npm包管理器
    5. 原型、原型链
    6. 数组及常用方法
    7. 模块化

React入门

React项目文件解析(注意优先级)

  1. react.development.js
    1. react的核心库
  2. react-dom.development.js
    1. react扩展库
  3. babel.min.js
    1. es6语句解析为es5语句
    2. jsx语句解析为js

hello react

React全家桶_第1张图片


<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>
<body>
    <div id="test">div>

    
    <script src="https://unpkg.com/react@16/umd/react.development.js">script>
    
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js">script>
    
    <script src="https://unpkg.com/[email protected]/babel.min.js">script>

    
    <script type="text/babel">
        // 1. 创建虚拟dom
        // 此处一定不要写引号,因为不是字符串
        const VDOM = <h1>hello react</h1>;

        // 2. 渲染虚拟dom到页面
        // ReactDOM.render(虚拟DOM, 渲染dom的位置)
        ReactDOM.render(VDOM, document.getElementById('test'));
    script>
body>
html>

使用jsx创建虚拟DOM(是通过原始js的语法糖)

React全家桶_第2张图片

不使用jsx创建虚拟DOM

React全家桶_第3张图片

真实Dom和虚拟Dom

关于虚拟DOM:

  1. 本质是Object类型的是对象(一般对象)。
  2. 虚拟DOM比较“轻”,真实DOM比较“重”,因为虚拟DOM是React内部在使用,无需真实DOM那么多的属性。
  3. 虚拟DOM最终会被React转换为真实DOM,呈现在页面上。

JSX的语法规则

  1. 全称:JavaScript XML
  2. react定义的一种类似于XML的JS扩展语法:JS + XML(XML早期用于存储和传输数据,后来用JSON存储传输数据)
  3. 本质是React.createElement(component,props,…children)方法的语法糖
  4. 作用:用来简化虚拟DOM
    1. 写法: var ele =

      hello jsx

    2. 注意1:它不是字符串,也不是HTML/XML标签
    3. 注意2: 他最终产生的是一个js对象
  5. 标签名任意:HTML标签或其他标签
    React全家桶_第4张图片

js表达式与语句的区别

  1. 表达式: 一个表达式会产生一个值,可以放在任何一个需要值的地方
    1). a (变量名)
    2). a+b
    3). demo(1) (函数调用表达式)
    4). arr.map()
    5). function test() {} (匿名函数)

  2. 语句(代码):控制代码走向的,没有值,不属于表达式
    1). if() {}
    2). for() {}
    3). switch() {case: xxx}
    React全家桶_第5张图片
    React全家桶_第6张图片

模块与组件,模块化与组件化的理解

模块

  1. 理解:向外提供特定功能的js程序,一般就是一个js文件
  2. 为什么要拆成模块:随着业务逻辑的增加,代码越来越多
  3. 作用:复用js,简化js的编写,提高js的运行效率

组件

  1. 理解:用来实现局部功能效果的代码和资源的集合(html/css/js)
  2. 为什么:一个界面的功能更复杂
  3. 作用:复杂编码,简化项目编码,提高运行效率

模块化

当应用的js都以模块来编写,这个应用就是模块化的应用。

组件化

当应用都是以多组件的方式来实现的,这个应用就是一个组件化的应用。

React面向组件编程

React组件分类

  1. 函数式组件(用函数定义的组件,适用于简单的定义)
    React全家桶_第7张图片

  2. 类式组件(用类定义的组件)
    总:
    1. 类中的构造器不是必须写的,要对实例进行一些初始化操作,才写(如添加指定属性)。
    2. 如果A类继承了B类,且A类中写了构造器,那么A类构造器中的super必须要调用
    3. 类中定义的方法,都是放在类的原型对象上,供实例去使用
    React全家桶_第8张图片
    React全家桶_第9张图片

组件实例的三大核心属性(state,props,refs在组件的实例上)(前提建立在类上面)

state

  1. 类中方法的实例指向
    React全家桶_第10张图片
  2. 类中的事件方法
    React全家桶_第11张图片
    简写形式(开发常用的方式):
    React全家桶_第12张图片
    注意:
    1)组件中 的render方法中的this为组件的实例对象
    2)状态数据,不能直接修改或更新
    3)组件自定义的方法中this为undefined,如何让解决?
    1. 强制绑定this,通过bind()方法来改变this的指向问题
    2. 箭头函数

props

React全家桶_第13张图片
展开运算符温故:
React全家桶_第14张图片
传递多参数(展开运算符的使用)
React全家桶_第15张图片
参数的传递限制(prop-type.js)
React全家桶_第16张图片
React全家桶_第17张图片
props传递参数的简写形式
将标签属性的限制和标签属性默认值的设置写在所用类里面,通过state关键字来定义
React全家桶_第18张图片
构造器
构造器是否接受props,是否传递super,取决于:是否需要在构造器中通过this访问props
React全家桶_第19张图片

构造器的使用情况:

  1. 通过给this.state赋值对象来初始化内部的state(在方法中使用构造器里面的数据值)
  2. 为事件处理函数绑定实例(通过bind方法改变this指向)

函数式组件使用props
注意:
函数式组件只能使用实例属性中的props属性,函数式组件没有state关键字,只能通过函数名.propTypes/defaultTypes来控制传递传输的类型和参数默认值。
React全家桶_第20张图片

refs(标识,相当于原生js 里获取的dom节点的id)

组件内的标签可以定义ref来标识自己

  1. 字符串形式的ref(存在效率问题,现官方已经不推荐使用了)React全家桶_第21张图片
  2. 回调函数形式的ref
    回调函数的特点:定义了,但没调用,却执行了。
    React全家桶_第22张图片
    回调函数中ref执行次数:
    在更行过程中它会执行两次,第一次传入参数null,第二次传入参数DOM元素。这是因为在每次渲染时会创建一个新的函数实例,然后React清空旧的ref并且设置新的。通过ref的回调函数定义成class的绑定函数的方式可以避免上述问题,但是大多数情况下是无关紧要的。
    React全家桶_第23张图片
  3. createRef(最推荐的一种写法)
    React全家桶_第24张图片

react中的事件处理

1).通过onXxx属性处理函数(注意大小写)
a. React使用的是自定义事件,而不是原生DOM事件————为了更好的兼容性
b.React中的事件是通过事件委托的方式实现的(委托给组件最外层的元素)————进行事件冒泡,就相当于在ul上面加事件,而不是在li上面加事件(为了高效)
2).通过event.target得到发生事件的DOM元素对象————发生事件的元素就是要操作的元素的时候使用,通过event.target.value来操作DOM对象(避免过度使用ref)

收集表单数据

表单组件的分类:
1. 受控组件(将数据通过onchange事件存储在state里面,用的时候就取,相当于vue里面的v-modal,双向数据绑定)【推荐使用这个】
React全家桶_第25张图片

3. 非受控组件(页面中的表单控件现用现取)

React全家桶_第26张图片

高阶函数及函数的柯里化

向对象里面插入数据:
React全家桶_第27张图片
** 高阶函数: **
如果一个函数符合下面2个规范中的任意一个,就是高阶函数

  1. 若A函数,接收的参数是一个函数,那么A就是一个高阶函数
  2. 若A函数,调用的返回值任然是一个函数,那么A也可以称之为高阶函数
    常见的高阶函数有: Promise、setTimeout、arr.map等

函数的柯里化: 通过函数调用继续返回函数的方式,实现多次接受参数最后统一处理的函数的编码形式。
React全家桶_第28张图片

React全家桶_第29张图片
不通过函数柯里化实现用户数信息弹出展现:
React全家桶_第30张图片

组件的生命周期回调函数

通过组件的生命周期实现页面效果的渐变:
React全家桶_第31张图片

生命周期函数之求和(旧)

在这里插入图片描述
如图:setState(更新,受阀门的控制),forceUpdate(强制更新,不受阀门的控制)

组件生命周期(组件生周期的执行顺序和代码顺序无关):

  1. 初始化状态(constructor)
  2. 组件将要挂载的钩子(componentWillMount)
  3. 组件的渲染(render)
  4. 组件在挂载完毕的钩子(componentDidMount)
  5. 组件将要卸载的钩子(componentWillMountUnmount)
  6. 控制组件更新的阀门(shouldComponentUpdate————写了这个钩子函数,必须要有返回值默认为true
  7. 组件将要更新的钩子(componentWillUpdate)
  8. 组件更新完毕的钩子(componentDidUpdate)
  9. 组件将要接收新的props的钩子(componentWillReceiveProps——注意:第一次接收的参数不算)

生命周期的三个阶段(旧):

  1. 初始化阶段:由ReactDOM.render()触发的一次渲染
    1.1. constructor()
    1.2. componentWilMount()
    1.3. render()
    1.4. componentDidMount()
  2. 更新阶段:由组件内部this.setState()或父组件重新render()触发
    1.1. shouldComponentUpdate()
    1.2. componentWillUpdate()
    1.3. render()
    1.4. componentDidUpdate()
  3. 卸载组件:由ReactDOM.unmountComponentAtNode()触发
    1.1 componentWillUnmount

常用的生命钩子:
render(组件的渲染),componentDidMount(页面加载完毕,一般在这个钩子中做初始化,例如开启定时器、发送网络请求、订阅消息),componentWillUnmount(组件将要更新的钩子,一般在这个狗子中做收尾的事,例如关闭定时器、取消订阅)

React应用(基于react脚手架)

下载安装react脚手架

  1. 全局安装脚手架
    npm i g create-react-app
    
  2. 通过脚手架创建项目
create-react-app demo(项目名称)
  1. 运行项目(注意:要切换到项目文件夹下运行)
npm start

nanoid唯一ID生成器的使用

下载安装nanoid,在项目文件中引用nanoid,然后通过nanoid()来调用

npm i nanoid

React全家桶_第32张图片

React全家桶_第33张图片

脚手架中的类型限制(prop-types)

注意:脚手架生成的项目依赖包中没有props-types类型限制包,要使用类型限制包,需要自己手动下载。

下载步骤:

  1. 切换到项目文件夹下
  2. 运行npm add prop-types,生成类型限制依赖
    React全家桶_第34张图片

todoList案例

最终效果:
React全家桶_第35张图片

项目主要文件:
React全家桶_第36张图片

  1. index.js —— 项目入口文件
    React全家桶_第37张图片

  2. App.jsx

// 创建外壳组件
import React, { Component } from "react";
import Header from './component/Header';
import List from './component/List';
import Footer from './component/Footer';
import './App.css';

// 创建并暴露App组件
export default class App extends Component {
  // 初始化状态
  state = {
    todos: [
      { id: '001', name: '肖申克的救赎', done: true },
      { id: '002', name: '神探夏洛克', done: true },
      { id: '003', name: '小时代', done: false }
    ]
  }
  // 添加列表
  addTodo = (todoObj) => {
    // 获取原来的todos
    const {todos} = this.state;
    // 追加一个todo
    const newTodos = [todoObj, ...todos];
    // 更新状态
    this.setState({todos:newTodos});
  }
  // 更新列表
  changeTodo = (id, done) => {
    // 获取状态中的todos
    const {todos} = this.state;
    const newTodos = todos.map((todoObj) => {
      if(todoObj.id === id) return {...todoObj, done}
      else return todoObj
    })
    this.setState({todos: newTodos})
  }
  // 删除列表
  deletTodo = (id) => {
    // 获取原来的todos
    const {todos} = this.state;
    // 删除指定id的对象
    const newTodos = todos.filter((todoObj) => {
      return todoObj.id !== id;
    });
    // 更新状态
    this.setState({todos: newTodos});
  }
  // 全选
  checkedAllTodo = (done) => {
    // 获取原来的todos
    const {todos} = this.state;
    // 加工数据
    const newTodos = todos.map((todoObj) => {
      return {...todoObj, done};
    });
    // 更新状态
    this.setState({todos: newTodos});
  }
  // 清除全选
  clearAllDone = () => {
    // 获取原来的todos
    const {todos} = this.state;
    // 过滤数据
    const newTodos = todos.filter(todoObj => !todoObj.done);
    // 更新状态
    this.setState({todos: newTodos});
  }

  render() {
    const { todos } = this.state;
    return (
      <div>
        <div className="todo-container">
          <div className="todo-wrap">
            <Header addTodo={this.addTodo} />
            <List todos={todos} changeTodo={this.changeTodo} deletTodo={this.deletTodo}/>
            <Footer todos={todos} checkedAllTodo={this.checkedAllTodo} clearAllDone={this.clearAllDone}/>
          div>
        div>
      div>
    )
  }
}
  1. App.css
/*base*/
body {
     
  background: #fff;
}

.btn {
     
  display: inline-block;
  padding: 4px 12px;
  margin-bottom: 0;
  font-size: 14px;
  line-height: 20px;
  text-align: center;
  vertical-align: middle;
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
  border-radius: 4px;
}

.btn-danger {
     
  color: #fff;
  background-color: #da4f49;
  border: 1px solid #bd362f;
}

.btn-danger:hover {
     
  color: #fff;
  background-color: #bd362f;
}

.btn:focus {
     
  outline: none;
}

.todo-container {
     
  width: 600px;
  margin: 0 auto;
}
.todo-container .todo-wrap {
     
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 5px;
}
  1. Header.jsx
import React, { Component } from 'react';
import PropsTypes from 'prop-types';
import {nanoid} from 'nanoid';
import './index.css'

export default class Header extends Component {
    // 对接收的props进行类型、必要性的限制
    static propType = {
        addTodo: PropsTypes.func.isRequired
    }
    handleKeyUp = (event) => {
        // 解构赋值获取keyCode, target
        const {keyCode, target} = event;
        // 判断是否是回车
        if(keyCode !== 13) return;
        // 处理输入的数据
        if(target.value.trim() === '') {
            alert('输入的信息不能为空');
            return;
        }
        // 准备好一个todo对象
        const todoObj = {id: nanoid(),name: target.value,done: false}
        // 将todoObj传递给App
        this.props.addTodo(todoObj);
        // 清空输入
        target.value = '';
    }
    render() {
        return (
            
) } }
  1. Header.css
/*header*/
.todo-header input {
     
    width: 560px;
    height: 28px;
    font-size: 14px;
    border: 1px solid #ccc;
    border-radius: 4px;
    padding: 4px 7px;
  }
  
  .todo-header input:focus {
     
    outline: none;
    border-color: rgba(82, 168, 236, 0.8);
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
  }
  1. List.jsx
import React, { Component } from 'react';
import PropsTypes from 'prop-types';
import Item from "../Item";
import './index.css'

export default class List extends Component {
    // 对接收的props进行类型、必要性的限制
    static propType = {
        todos: PropsTypes.array.isRequired,
        changeTodo: PropsTypes.func.isRequired,
        deletTodo: PropsTypes.func.isRequired
    }
    render() {
        const {todos, changeTodo, deletTodo} = this.props;
        return (
            
    { todos.map((todo) => { return }) }
) } }
  1. List.css
/*main*/
.todo-main {
     
    margin-left: 0px;
    border: 1px solid #ddd;
    border-radius: 2px;
    padding: 0px;
}

.todo-empty {
     
    height: 40px;
    line-height: 40px;
    border: 1px solid #ddd;
    border-radius: 2px;
    padding-left: 5px;
    margin-top: 10px;
}
  1. Item.jsx
import React, { Component } from 'react';
import './index.css';

export default class Item extends Component {
    state = {mouse: false}
    // 鼠标移入移出的回调
    handleMouse = (target) => {
        return () => {
            this.setState({mouse: target});
        }
    }
    // 删除列表的回调
    handleDelete = (id) => {
        if(window.confirm('确定删除吗?')){
            this.props.deletTodo(id);
        }
    }
    // 勾选和取消勾选的回调
    handleChange = (id) => {
        return (event) => {
            this.props.changeTodo(id, event.target.checked);
        }
    }
    render() {
        const {id, name, done} = this.props;
        const {mouse} = this.state;
        return (
            
  • ) } }
    1. Item.css
    /*item*/
    li {
         
        list-style: none;
        height: 36px;
        line-height: 36px;
        padding: 0 5px;
        border-bottom: 1px solid #ddd;
      }
      
      li label {
         
        float: left;
        cursor: pointer;
      }
      
      li label li input {
         
        vertical-align: middle;
        margin-right: 6px;
        position: relative;
        top: -1px;
      }
      
      li button {
         
        float: right;
        display: none;
        margin-top: 3px;
      }
      
      li:before {
         
        content: initial;
      }
      
      li:last-child {
         
        border-bottom: none;
      }
    
    1. Footer.jsx
    import React, { Component } from 'react';
    import './index.css';
    
    export default class Footer extends Component {
        // 全选checkbox的回调
        handleCheckedAll = (event) => {
            this.props.checkedAllTodo(event.target.checked);
        }
        // 清除所有已完成的回调
        handleClearAll = () => {
            this.props.clearAllDone()
        }
        render() {
            const {todos} = this.props;
            // 已完成的个数(对数组进行条件统计)
            const doneCount = todos.reduce((pre, todos) => pre + (todos.done ? 1 : 0), 0);
            // 总数
            const total = todos.length; 
            return (
                
    已完成{doneCount} / 全部{total}
    ) } }
    1. Footer.css
    /*footer*/
    .todo-footer {
         
       height: 40px;
       line-height: 40px;
       padding-left: 6px;
       margin-top: 5px;
     }
     
     .todo-footer label {
         
       display: inline-block;
       margin-right: 20px;
       cursor: pointer;
     }
     
     .todo-footer label input {
         
       position: relative;
       top: -1px;
       vertical-align: middle;
       margin-right: 5px;
     }
     
     .todo-footer button {
         
       float: right;
       margin-top: 5px;
     }
    

    todoList案例相关知识点

    1. 拆分组件、实现静态组件,注意:className、style的写法
    2. 动态初始化列表,如何确定将数据放在那个组件的state中?
      ——某个组件使用:放在自身的state中
      ——某些组件使用:放在他们共同的父组件state中(官方称此操作为:状态提升)
    3. 关于父子之间通信
      1. 【父组件】给【子组件】传递数据:通过props
      2. 【子组件】给【父组件】传递数据:通过props传递,要求父提前给子组件传递一个函数
    4. 注意defaultChecked和checked的区别,类似的还有:defaultValue和value
    5. 状态在哪里,操作状态的方法就在那里

    react ajax

    前置说明

    1. React本身支付按住于界面,并不包含发发送ajax请求的代码
    2. 前端应用需要通过过ajax请求与后台进行交互(json数据)
    3. React应用中需要继承第三方ajax库(或者自己封装)

    常用的ajax请求库

    1. JQuery:比较重,如果需要另外引入不推荐使用
    2. axios:轻量级,建议使用
      1. 封装XmlHttpRequest对象的ajax
      2. Promise风格
      3. 可以用在浏览器端和node服务器端

    使用axios

    1. 手动安装axios
      在这里插入图片描述
    2. 通过axios.get请求服务器地址
      React全家桶_第38张图片
    3. 跨域解决方案
      一、在package.json配置文件中,加上配置代理,添加配置项后,要重启脚手架(仅限于一个接口使用)
      axios.get请求的数据接口要变成http:\\localhost:5000,这样写相当于3000没有的找5000要,这样只能配置一个服务器接口,局限性太小了。
      React全家桶_第39张图片
      说明:
      优点:配置简单、前端请求资源时可以不加任何前缀
      缺点:不能配置多个代理
      工作方式:上述方式配置代理,当请求了3000不存在的资源时,那么该请求会转发给5000(优先匹配前端资源)

    二、在Ract项目中配置多台代理

    1. 创建代理配置文件
      在src下创建配置文件:setupPoxy.js
    2. 编写setupPoxy.js配置具体规则:
      React全家桶_第40张图片
      说明:
      优点:可以配置多个代理,可以灵活的控制请求是否代理
      缺点:配置繁琐,前端请求资源时必须加前缀

    解构赋值

    解构赋值:常规解构赋值和连续解构赋值。
    React全家桶_第41张图片

    同级组件(兄弟组件)之间的通信

    消息订阅与发布机制

    1. 工具库:PubSubJS
    2. 下载: npm i pubsub-js --save
    3. 使用:
      1. import PubSub from ‘pubsub-js’——引入
      2. PubSub.subscribe(‘delete’, function(data){})——订阅
      3. PubSub.publish(‘delete’,data) ——发布消息
      React全家桶_第42张图片
      1. 先订阅,在发布j
      2. 适用于任何组件之的通信
      3. 要在组件的componentWillUnmount中取消订阅

    Fetch发送请求(关注分离的设计思想)

    特点:

    1. fetch是原生的函数,不再使用XmlHttpRequest对象提交ajax请求
    2. 老版本浏览器可能不支持
    try {
         
    	const response = await fetch(`/api1/search/user?q=${
           keyword}`);
    	const data = await response.json();
    } catch(error ){
         
    	console.log(error);
    }
    

    react-router

    SPA的理解

    1. 单页面应用
    2. 整个应用只有一个完整的页面
    3. 点击页面中的链接不会刷新页面,只会做页面的局部刷新
    4. 数据都需要通过ajax请求获取,并在前端异步实现

    路由

    什么是路由?

    1. 一个路由就是一个映射关系(key:value 或者 path:component)
    2. key为路径,value可能是一个方法或者一个组件

    路由分类

    1. 后端路由:
      1. 理解:value是function,用来处理客户端提交的请求
      2. 注册路由: rooter.get(path,function(req, res))
      3. 工作过程:当node接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据
    2. 前端路由:
      1. 浏览器端路由:value是component,用于展示页面内容
      2. 注册路由:history.push('/test');' history.replace('/test'); history.goback(); history.listen((localhost) => { console.log(localhost); })

      react-router-dom的理解

      1. react的一个插件库
      2. 专门实现一个SPA应用
      3. 基于react的项目都会用到此库

      react-router-dom相关API

      使用

      1. 下载安装react-router-dom
        在这里插入图片描述
      2. 在使用界面引入相关依赖,结合路由使用
        React全家桶_第43张图片React全家桶_第44张图片
        React全家桶_第45张图片
        路由的基本使用:
        1. 明确好界面中的导航区、展示区
        2. 导航区的a标签改为Link标签
        3. 展示区的Router标签进行路径的匹配
        4. 的最外侧包裹了一个< BrowerRouter >或< HashRouter >

      组件

      分类:一般组件和路由组件,一般组件放在components文件夹下班,路由组件放在pages文件夹下。
      区别:
      1. 一般组件通过标签来引用,参数传什么,就收到什么,例如< Header >
      2. 路由组件靠路由匹配,供路由跳转的时候使用,不用传参,就可以收到内置参数(history,location,match)
      React全家桶_第46张图片

      NavLink的使用

      React全家桶_第47张图片
      在这里插入图片描述
      Link没有active效果,NavLink点谁就给谁加上了active效果.
      React全家桶_第48张图片

      NavLink组件的封装

      标签体内容是一种特殊的标签属性。
      封装:

      import React, {
            Component } from 'react';
      import {
            NavLink} from "react-router-dom";
      
      export default class  extends Component {
           
          render() {
           
              return (
                  <NavLink activeClassName="active" className="list-group-item" {
           ...this.props}/>
              )
          }
      }
      

      使用:

      import MyNavLink from './component/MyNavLink';
       <MyNavLink to="/about">About</MyNavLink>
      <Route path="/about" component={
           About} />
      

      Switch的使用

      通常情况下,path和component是一一对应的关系
      Switch可以提高路由匹配效率(单一匹配)

      1. 引入
      import {
            Route, Switch } from "react-router-dom";
      
      1. 使用
      <Switch>
      	<Route path="/about" component={About} />
      	 <Route path="/home" component={Home} />
      Switch>
      

      样式丢失的解决方法

      1. 使用绝对路径引用样式表(常用)
        React全家桶_第49张图片
      2. 使用 public文件的绝对路径%PUBLIC_URL%引用样式表(常用)
        在这里插入图片描述
      3. 使用HashRouter
        React全家桶_第50张图片
        #后面的资源都认为是前端资源,不会出现样式的丢失。
        React全家桶_第51张图片

      路由的严格匹配和模糊匹配

      模糊匹配:
      to(可以多) —— path(从左到右匹配,顺序不能变)
      默认使用模糊匹配,【输入的路径】必须包含要【匹配的路径】,且顺序要一致。
      React全家桶_第52张图片
      严格匹配:
      React全家桶_第53张图片
      **注意:**严格匹配不要随便开启,需要再开,有时候开启会导致无法匹配二级路由。

      路由重定向 Redirect(默认匹配页面第一次加载选中的组件)

      一、引入
      React全家桶_第54张图片
      一、使用
      注意:Redirect一定要写在Route的最后面。
      React全家桶_第55张图片

      嵌套路由

      React全家桶_第56张图片
      注意:

      1. 注册子路由时要写上父路由的path值
      2. 路由的匹配规则是按照注册顺序执行的

      向路由组件中传递数据

      1. params参数
        路由链接(携带参数): /home/message/detail${msgObj.id}/${msgObj.title}}>{msgObj.title}
        注册路由(声明接收):{/* 声明接收params参数 */}

        接收参数:const { id, title } = this.props.match.params; 在这里插入图片描述
        在这里插入图片描述

      React全家桶_第57张图片

      1. search参数
        在这里插入图片描述
        在这里插入图片描述
        React全家桶_第58张图片
      2. state参数(在地址栏中没有参数,刷新也可以保留住参数)
        在这里插入图片描述
        在这里插入图片描述
        React全家桶_第59张图片

      路由跳转的两种模式

      1. push跳转(默认push跳转)
        页面跳转有痕迹,可以回到上一页
      2. replace跳转
        页面跳转不留下痕迹,浏览器中没有左右切换(上一页/下一页)的按钮

      编程式路由导航

      1. replace跳转+携带params
      this.props.history.replace(`/home/message/detail/${msgObj.id}/${msgObj.title}`);
      
      1. replace跳转+携带search
      this.props.history.replace(`/home/message/detail/id=${msgObj.id}&title=${msgObj.title}`);
      
      1. replace跳转+携带state
      this.props.history.replace(`/home/message/detail`,{id: msgObj.id,title:  msgObj.title});
      

      注:
      借助this.props.history对象上的API对操作路由进行跳转、前进、后退
      this.props.history.push()
      this.props.history.replace()
      this.props.history.goBack()
      this.props.history.goForward()
      this.props.history.go()——传的number值为正数,就前进几步,为负数就后退几步

      widthRouter 的使用(一般组件不能使用路由组件里面的API怎么解决)

      widthRouter可以加工一般组件,让一般组件具备路由组件所持有的API;widthRouter的返回值是一个新组件。

      import {
           widthRouter} from 'react-router-dom';
      
      class Header extends Component {
           
      	back = () => {
           
      		this.props.history.goBack();
      	}
      }
      
      export default widthRouter(Header);
      

      BrowserRouter与HashRouter的区别

      1. 底层原理不一样:
        BrowserRouter使用的式H5的history API,不兼容IE9及以下版本
        HashRouter使用的是URL的哈希值
      2. path表现形式不一样
        BrowserRouter的路径中没有#,例如localhost:3000/demo/index
        HashRouter的路径中有#,例如localhost:3000/#/demo/index
      3. 刷新后对路由state参数的影响
        BrowserRouter没有任何影响,因为state保存在history对象中
        HashRouter刷新后会导致路由state参数丢失
      4. 备注:HashRouter可以用于解决一些路径错误相关的问题

      react UI组件库

      流行的开源组件UI库

      1. ant-design(国内蚂蚁金服)
      2. material-ui(国外)

      使用步骤:

      1. 安装
      npm add antd
      
      1. 使用
        React全家桶_第60张图片

      按需引入antd样式库

      React全家桶_第61张图片
      React全家桶_第62张图片
      React全家桶_第63张图片

      React全家桶_第64张图片
      React全家桶_第65张图片

      设置自定义主题颜色

      React全家桶_第66张图片
      React全家桶_第67张图片

      一步到位

      1.安装依赖:yarn add react-app-rewired customize-cra babel-plugin-import less less-loader
      2.修改package.json

      “scripts”: {
      “start”: “react-app-rewired start”,
      “build”: “react-app-rewired build”,
      “test”: “react-app-rewired test”,
      “eject”: “react-scripts eject”
      },

      3.根目录下创建config-overrides.js
      //配置具体的修改规则
      const { override, fixBabelImports,addLessLoader} = require(‘customize-cra’);
      module.exports = override(
      fixBabelImports(‘import’, {
      libraryName: ‘antd’,
      libraryDirectory: ‘es’,
      style: true,
      }),
      addLessLoader({
      lessOptions:{
      javascriptEnabled: true,
      modifyVars: { ‘@primary-color’: ‘green’ },
      }
      }),
      );
      4.备注:不用在组件里亲自引入样式了,即:import 'antd/dist/antd.css’应该删掉

      redux

      redux是什么

      1. redux是一个专门用于做于状态管理的js库(不是react插件库)
      2. 它可以用在react,angular,vue等项目中,但不基于react配合使用
      3. 作用:集中式管理react应用中多组件共享的状态

      什么情况下需要使用redux

      1. 某个组件的状态,需要让其他组件可以随时拿到(共享)
      2. 一个组件需要改变另一个组件的状态(通信)
      3. 总体原则:能不用就不用,如果不用比较吃力才考虑使用

      redux工作流程

      React全家桶_第68张图片

      reduix的三个核心对象

      action

      1. 动作的对象
      2. 包含的两个属性
        1. type:标识属性,值为字符串,唯一,必要属性
        2. data:数据属性,值为任意类型,可选属性

      reducer

      1. 用于初始化状态、加工状态
      2. 加工时,根据旧的state和action,产生新的state的纯函数

      store

      1. 将state、action、reducer联系在一起
      2. 如何得到此对象?

      redux精简版

      1. 去除组件自身的状态
      2. 在src文件下建立
        src——redux——store.js/count_renducer.js
      3. store.js
        引入redux中的createStore函数,创建一个store
        createStore调用时要传入一个为其服务的reducer
        记得暴露store对象
      4. count_render.js
        renducer的本质是一个函数,接收:preState,action,返回加工后的状态
        renducer有两个作用:初始化状态、加工状态
        renducer被第一次调用时,时store自动触发的,传递的preState是undefined
      5. 在index.js中检测store状态的改变,一旦发生改变重新渲染
        备注:redux只负责管理状态,至于状态的改变驱动着页面的展示,要靠我们自己写。

    你可能感兴趣的:(笔记,资料分享,javascript,react,学习笔记)