react知识点

本文详细介绍了React的基础概念,包括JSX语法、组件化、虚拟DOM、生命周期方法和状态管理。深入讲解了如何创建组件、使用props和state、处理事件、使用refs以及如何进行状态管理和路由配置。此外,还涵盖了React的优化技巧,如使用PureComponent、Hooks和Redux。最后,探讨了React Router的配置和使用,以及如何处理组件间的通信。
摘要由CSDN通过智能技术生成

react

是什么?

react就是一个用于构建用户界面的javascripte库

react facebook出品 2013年6月发布 2013年9月 就受到了全世界开发者的追捧

为什么有这么多第三方的js框架 facebook还要开发react?

facebook需要解决当下技术的一个问题:项目在逐渐变大(需要有大量页面内容改变-----》大量的dom操作)性能低下

页面改变-----》大量的dom操作----》浪费性能

页面改变-----》大量的dom操作( 自动dom操作 状态数据直接对应页面展示 )把dom操作不由浏览器来进行 而是react帮助他来进行dom的相关操作

虚拟DOM

虚拟DOM相当于就是在真实DOM中添加一个一个缓存 基于react在开发的时候把所有的真实DOM通过react变成虚拟的

好处就是每当数据变化的时候 react就会把页面的dom改变进行相关的处理 减少了更新的事件(真实dom只要数据变了一点点那么都会把整个dom树删除掉重新创建) react在操作dom的时候是尽可能少的减少更新的区域 加快了更新的事件

diff

diff是一个算法 协助虚拟dom去发现哪里改变了 就可以计算出虚拟dom中真正改变的部分是什么 协助虚拟dom只针对改变的区域进行dom操作 而不是把整个页面改变

虚拟dom配合diff就可以尽可能少的改变页面区域加快更新事件 降低性能损耗

react特点

1.组件化

2.声明式渲染设计

3.高效

4.灵活

5.单向数据流

组件特点

强内聚 弱耦合

1.提高了代码的复用性

2.降低了测试难度

3.降低了代码的复杂度

兼容新

ie8以下不要想了

开发环境的搭建

1,下载包

react核心包 包含react的核心代码

react-dom包 react面向浏览器端的相关核心代码

babel 包 就是把浏览器不认识的代码翻译成浏览器认识的代码

npm install --save react react-dom babel-standalone

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 1.引包   注意 必须严格按照顺序引用 先引react 在引react-dom -->
    <script src="./node_modules/react/umd/react.development.js"></script>
    <script src="./node_modules/react-dom/umd/react-dom.development.js"></script>
    <script src="./node_modules/babel-standalone/babel.js"></script>
</head>
<body>
    <!-- 2.设置根节点 -->
    <div id="demodiv">
​
    </div>
    <script type="text/babel">
        // 下面的这段代码  既不是js   也不是html  
        // JSX javascript xml的简称   一种语法要求比较严格的一种新的格式  jsx可以帮助react更好的
        // 来完成页面的开发
​
        // 特点:
        // 1.jsx执行效率更高
        // 2.语法要求严谨 写代码的时候更安全
        // 3.使用jsx在编写界面的时候更简单
​
        // jsx  遇见< 当html解析    遇见{} 当js解析
        let el=<h1>你好么么哒</h1>
​
        // render方法就是渲染的意思
        ReactDOM.render(el,document.getElementById("demodiv"))
    </script>
</body>
</html>

jsx

下面的这段代码 既不是js 也不是html

let el=<h1>你好么么哒</h1>

JSX javascript xml的简称 一种语法要求比较严格的一种新的格式 jsx可以帮助react更好的来完成页面的开发

特点: 1.jsx执行效率更高 2.语法要求严谨 写代码的时候更安全 3.使用jsx在编写界面的时候更简单

jsx 遇见< 当html解析 遇见{} 当js解析

坑1

jsx坑1  多行jsx  必须要有一个父容器包裹
        let el=(
                <div>
                        <h1>1111</h1>
                        <h1>2222</h1>
                </div>
                )   

坑2插变量

坑2 jsx怎么插变量
          let text="你好么么哒";  
          let el=(
                <div>
                        <h1>{text}</h1>
                        <h1>2222</h1>
                </div>
                )   

坑3 属性插变量

坑3  属性插变量
            let text="点我去百度"
            let ahref="http://www.baidu.com"
            let el=(
                <a href={ahref}>{text}</a>
            )

坑4 注释

​
           let el=(
                <div>
                        {/*注释我*/}
                        
                        <h1>1111</h1>
                        <h1>2222</h1>
                </div>
                ) 

坑5 jsx严谨的

严谨的 必须按照W3C规范来完成 标签必须闭合
           let el=(
                <div>
                    <input type="text"/>
                </div>
                )

坑6 行内样式设置

行内样式
               let el=(
                <div>
                     
                        {/*
                        行内样式必须对应一个对象来完成
                        所以外层的{}是jsx解析js的语法  里面的{}是对象的语法
                        */}
                        <h1 style={{color:"red",backgroundColor:"yellow"}}>1111</h1>
                        <h1>2222</h1>
                </div>
                ) 

坑7 类样式

类样式 我们之前都是使用class 来给dom起名字

但是到了react中不行了 因为class 是es6类的关键字 所以在react中如何想起类名那么需要把原来的class属性改成className来完成

cra-----create-react-app 脚手架

创建脚手架

1.全局下载脚手架 npm install -g create-react-app

2.测试安装是否成功 查看版本 create-react-app --version

3.cd到指定文件夹下

4.创建项目 create-react-app 项目名

5 cd到项目下

6 启动项目

你去公司了 怎么启动项目? 来到项目下找到package.json文件 找到scripts节点即可看到

启动命令就是 npm run 加scripts上的内容

但是 所有内容中 start可以不加run 别的都必须加

拿到空项目怎么办?

1.写代码都在src下(会发现src下和vue不一样 连个文件夹都没有 react的文件夹需要我们自己创建 所以我们自己先创建一个components的文件夹)

2.删除app.js与app.css 两个文件 因为他俩是欢迎页面

3.创建我们自己的组件

4.在index.js中引用使用我们自己的组件

组件

组件分类

react中有两种组件的写法 一种叫函数组件(无状态组件) 第二种 叫类组件

类组件

语法:必须记住

class 组件名 extends React.Component{

render(){

return (

jsx

)

}

}

设置样式

1.你可以写行内样式

2.外部样式

新建.css文件来编写 起类名的时候 千万不要使用class 要用className

引用: import "css的相对路径"

import React, { Component } from 'react'
// 引用样式
import "../styles/homezi.css"
export default class homezi extends Component {
    render() {
        return (
            <div>
                我是子组件
                <h1 className="demoh">1111</h1>
            </div>
        )
    }
}
​

无状态组件函数组件

语法:

function 组件名(首字母必须大写){

return (

jsx

)

}

function Home(){
    return (
        <div>
            我是一个函数组件
        </div>
    )
}
​
export default Home

设置样式

同类组件

类组件与函数组件有什么区别?

无状态组件 创建的组件形式它的可读性要好于 类组件

无状态组件 在编写的时候减少了大量的冗余代码 减少了代码量

无状态组件 没有实例化的过程 所以渲染速度更高

无状态组件 减少了类组件中大量的this操作

通常情况下 如果大量使用到了函数组件的话 那么react的版本必须是大于16.8以上的(要大量使用函数组件必须要配合着react16.8新增的一个技术叫HOOK 后面会学习)

组件的使用

1.引用

2.使用

组件传值

正传---props

使用props来进行正向传值 props 组件对外部的接口 可以接收外部传递进来的数据

函数组件

1.子组件接收

// 把props当成形参传递到当前组件中
function Zi(props){
    return (
        <div>
            zizizizizizzi---{props.xiaoming}
        </div>
    )
}
export default Zi

2.父组件传递

import Zi from "./zi.jsx"
function Fu(){
    return (
        <div>
            fufufuffufufu
            {/* props的传递 */}
            <Zi xiaoming="我是props数据"/>
        </div>
    )
}
export default Fu

props验证

注意单词大小写

import PropTypes from 'prop-types'
​
function Zi(props){
    let {xiaoming,xiaohong}=props
    return (
        <div>
            zizizizizzizi{xiaoming}---{xiaohong}
        </div>
    )
}
// props验证  注意proptypes的单词大小写 上下两个不一样
Zi.propTypes={
    xiaoming:PropTypes.number
}
​
export default Zi
​
​
​
​
​

类组件

1.在子组件中接收父组件传递的参数 this.props.xxx

import React, { Component } from 'react'
​
export default class zi extends Component {
    render() {
        return (
            <div>
                {/* 子组件设置接收 */}
                zizizziziziz---{this.props.xiaoming}
            </div>
        )
    }
}
​

2.在子组件被调用的时候 <子组件 子组件的props名="值">

import React, { Component } from 'react'
​
import Zi from "./zi.jsx"
export default class fu extends Component {
    render() {
        return (
            <div>
                ffuifufufufufuf
                {/* 给子组件传递数据 */}
                <Zi xiaoming="我是正向传值的数据"/>
            </div>
        )
    }
}
​

优化写法

子组件解构props的数据 优化接收参数写法

import React, { Component } from 'react'
​
export default class zi extends Component {
    render() {
        // 使用解构解出需要的props数据
       let {xiaoming,xiaohong,xiaobai,xiaohei} = this.props
        return (
            <div>
                {/* 使用解构出的props数据*/}
                zizizziziziz---{xiaoming}
                <p>{xiaohong}</p>
                <p>{xiaobai}</p>
                <p>{xiaohei}</p>
            </div>
        )
    }
}
​

父组件传递的时候使用...扩展运算符

import React, { Component } from 'react'
​
import Zi from "./zi.jsx"
export default class fu extends Component {
    constructor(){
        super()
        this.state={
           obj:{
            xiaoming:"1我是正向传值的数据",
            xiaohong:"2红红",
            xiaobai:"3西北一枝花",
            xiaohei:"4嘿嘿"
           }
        }
    }
    render() {
        return (
            <div>
                ffuifufufufufuf
                {/* 给子组件传递数据 */}
                {/* <Zi xiaoming="我是正向传值的数据" xiaohong="红红" xiaobai="西北一枝花" xiaohei="嘿嘿"/> */}
                <Zi {...this.state.obj}/>
            </div>
        )
    }
}
​

props验证

自 React v15.5 起,React.PropTypes 已移入另一个包中。请使用 prop-types 库 代替。

import React, { Component } from 'react'
// 引用验证库文件
import PropTypes from 'prop-types'
​
export default class proptypes extends Component {
    // 声明验证类型
    static propTypes = {
        xiaoming: PropTypes.string
    }
​
    render() {
        return (
            <div>
                {this.props.xiaoming}
            </div>
        )
    }
}
​

this.props.children

表示当前组件的所有子元素

逆传

react 逆向传值 也必须使用事件来触发传递 同时也是通过props来进行的

1.通过事件来触发

import React, { Component } from 'react'
​
export default class zi extends Component {
    render() {
        return (
            <div>
                ziziziziziziz
                {/* 1.创建事件来进行逆向传值 */}
                <button onClick={}>点我逆向传值</button>
            </div>
        )
    }
}

2.想完成逆向传值 那么子组件需要接收一个父组件传递过来的函数

import React, { Component } from 'react'
​
export default class zi extends Component {
    render() {
        return (
            <div>
                ziziziziziziz
                {/* 1.创建事件来进行逆向传值 */}
                {/* 2.子组件定义一个接收参数 */}
                <button onClick={this.props.fun}>点我逆向传值</button>
            </div>
        )
    }
}
​

3.父组件开始给子组件传递需要的函数

import React, { Component } from 'react'
import Zi from "./zi.jsx"
export default class fu extends Component {
// 3.父组件定义函数
    fufun=()=>{
      
    }
​
    render() {
        return (
            <div>
                fufufufuffufu
                {/* 4.父组件给子组件把函数传过去 */}
                <Zi fun={this.fufun}/>
            </div>
        )
    }
}
​

4.子组件把数据当成函数的实参传递到这个函数中

​
​
import React, { Component } from 'react'
​
export default class zi extends Component {
    render() {
        return (
            <div>
                ziziziziziziz
                {/* 1.创建事件来进行逆向传值 */}
                {/* 2.子组件定义一个接收参数 */}
                {/* 5.子组件使用bind绑定参数给函数 */}
                <button onClick={this.props.fun.bind(this,"我是子的数据")}>点我逆向传值</button>
            </div>
        )
    }
}
​

5.父组件就在函数中定义形参接收参数并且 想怎么用就怎么用

import React, { Component } from 'react'
import Zi from "./zi.jsx"
export default class fu extends Component {
// 3.父组件定义函数
// 6.定义形参并且使用
    fufun=(num)=>{
      console.log(num);
    }
​
    render() {
        return (
            <div>
                fufufufuffufu
                {/* 4.父组件给子组件把函数传过去 */}
                <Zi fun={this.fufun}/>
            </div>
        )
    }
}
​

同胞传 --- pubsub-js

1.下载 npm install --save pubsub-js

2.抛出自定义事件 publish( "自定义事件名","传递的数据" )创建自定义事件

import React, { Component } from 'react'
// 1.引用pubsub
import PubSub from "pubsub-js"
export default class zi extends Component {
    constructor(){
        super()
        this.state={
            text:"我是zi的数据"
        }
    }
    fun=()=>{
        // 2.抛出自定义事件
        PubSub.publish("pao",this.state.text)
    }
    render() {
        return (
            <div>
                ziziziziziziz
                <button onClick={this.fun}>点我同胞传值</button>
            </div>
        )
    }
}
​

3.监听自定义事件 subscirbe("监听的事件名",(监听的事件名,参数)=>{})

import React, { Component } from 'react'
import PubSub from "pubsub-js"
export default class zib extends Component {
    // 自定执行监听
    componentDidMount() {
        // 监听自定义事件
        PubSub.subscribe("pao",(a,b)=>{
            console.log(a);//你监听的事件名
            console.log(b);//数据
        })
    }
    
    render() {
        return (
            <div>
                zizizizizibbbbbbb
            </div>
        )
    }
}
​

跨层级传

react的组件之间的传递 是单向传递 要一层一层的来进行 遇见跨层级方便数据传递的话就会很麻烦

context 上下文对象

context就是用来解决跨层级传递的一个技术 减少了跨层级跨组件传值的复杂度

要使用context对象 那么就需要使用 createContext() 来进行初始化创建

context对象中内置对象:

Provider 生产者--------》生产你要传递的数据

Consumer 消费者--------》使用生产的数据

使用:

1.在src下创建一个用来存放上下文对象的文件夹与文件

2.创建并引用createContext()

// 引用createContext
import React, { Component,createContext } from 'react'
​
export default class index extends Component {
    render() {
        return (
            <div>
                {/* 接收所有的子元素 */}
                {this.props.children}
            </div>
        )
    }
}
​

3.在全局配置文件中让上下文对象的组件变成所有组件的老大

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/ye.jsx';
import reportWebVitals from './reportWebVitals';
// 引用上下文对象
import Mycontext from "./context/index.js"
​
ReactDOM.render(
  // 包裹成为当前项目所有组件的父元素
  <Mycontext>
    <App />
  </Mycontext>,
  document.getElementById('root')
);
​
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
​

4.在回到上下文对象的文件中开始编写

// 引用createContext
import React, { Component,createContext } from 'react'
// 创建上下文对象
let context=createContext()
// 解构出生产者和消费者
let {Provider,Consumer}=context
​
 class index extends Component {
    render() {
        return (
            <div>
                {/* 生产者开始生产数据 */}
                <Provider value={666}>
                    {/* 接收所有的子元素 */}
                    {this.props.children}
                </Provider>
            </div>
        )
    }
}
​
// 因为默认情况下值暴露了 当前组件  但是现在还需要把消费者也一并暴露出去
export {index,Consumer}

5.修改原有的上下文对象暴露的组件名

// 引用createContext
import React, { Component,createContext } from 'react'
// 创建上下文对象
let context=createContext()
// 解构出生产者和消费者
let {Provider,Consumer}=context
​
 class Mycontext extends Component {
    render() {
        return (
            <div>
                {/* 生产者开始生产数据 */}
                <Provider value={666}>
                    {/* 接收所有的子元素 */}
                    {this.props.children}
                </Provider>
            </div>
        )
    }
}
​
// 因为默认情况下值暴露了 当前组件  但是现在还需要把消费者也一并暴露出去
export {Mycontext,Consumer}

6修改原有index.js中对上下文对象的引用

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/ye.jsx';
import reportWebVitals from './reportWebVitals';
// 引用上下文对象
import {Mycontext} from "./context/index.js"
​
ReactDOM.render(
  // 包裹成为当前项目所有组件的父元素
  <Mycontext>
    <App />
  </Mycontext>,
  document.getElementById('root')
);
​
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
​

7.想在哪里使用数据就在哪里使用数据 使用consumer来使用

import React, { Component } from 'react'
import {Consumer} from "../context/index.js"
export default class zi extends Component {
    render() {
        return (
            <div>
                zizziziziz
                <Consumer>
                    {
                        // 形参就是生产者生产出来的数据
                        (value)=>{
                            return (
                                <h1>{value}</h1>
                            )
                        }
                    }
                </Consumer>
            </div>
        )
    }
}
​

redux 难写的一批

redux 就是状态管理工具 reudx是一个第三方的状态管理工具 他可以在任何地方使用包括vue

创建一个公共的数据仓库 那个组件想用 那个组件就自己过来拿 免去了组件与组件的单向数据传递

redux 的三大特点

1.单一数据源 在一个项目中只存在一个redux对象

2.state是只读的 state就是reudx中存储数据的地方 如果要修改state action来修改state

3.使用纯函数来修改 使用一个一个的修改函数来进行数据的修改动作、

使用:

1下载 npm install --save redux

2.新建文件夹与文件 并且创建出redux对象

// 1.引用redux  并且获取到创建store对象的方法
import {createStore} from "redux"
​
// 2.开始创建redux对象
let store=createStore()
​
// 3.暴露
export default store

3.创建要管理的数据

// 1.引用redux  并且获取到创建store对象的方法
import {createStore} from "redux"
​
// 6创建数据
let data={
    name:"xixi",
    age:18
}
​
// 5.创建reudcer对象 state数据   action 保存修改动作
// 7.把数据当做函数形参默认值的方式传递给state
let reducer=(state=data,action)=>{
    return state
}
​
// 2.开始创建redux对象
// 4.引用reducer 对象 (里面保存这数据和修改的方法)
let store=createStore(reducer)
​
// 3.暴露
export default store

4.想在哪里用就在哪里用

import React, { Component } from 'react'
import store from "../store/index.js"
export default class demob extends Component {
    render() {
        return (
            <div>
                demob---{store.getState().name}
            </div>
        )
    }
}
​

reducer拆分

1.在store文件夹下创建一个新的文件夹用来容纳我们拆分的模块

let data={
  
    nameb:"我是demob的数据",
}
​
let demob=(state=data,action)=>{
    return state
}
​
export default demob

2.合并多个reducer

// 合并reducers文件夹中的多个reducer模块
// combineReducers把多个reducer模块合并成一个
import {combineReducers} from "redux"
​
import demobr from "./reducers/demobr.js"
import demor from "./reducers/demor.js"
​
// 开始合并
let reducer=combineReducers({
    demobr,
    demor
})
​
export default reducer

3.在使用的时候 store.getState().模块名。数据

修改

1.使用dispatch() 来触发修改动作

import React, { Component } from 'react'
import Demob from "./demob.jsx"
// 1.引用store对象
import store from "../store/index.js"
export default class demo extends Component {
​
    fun=()=>{
        store.dispatch({type:"USERDATA_LIST_TITLE_ADD"})
    }
    funb=()=>{
        store.dispatch({type:"USERDATA_LIST_TITLE_DEL"})
    }
​
    render() {
        return (
            <div>
                使用redux存储的数据---{store.getState().demor.name}
                <div>
                    <button onClick={this.fun}>点我添加数据</button>
                    <button onClick={this.funb}>点我减少数据</button>
                </div>
                <Demob/>
            </div>
        )
    }
}
​

2.在reducer模块中添加修改的动作

let data={
    name:123,
    text:"aaaa",
    textb:"bvbbaaaa"
​
}
// action中保存的就是一个个的修改任务
let demo=(state=data,action)=>{
​
    switch (action.type) {
        case "USERDATA_LIST_TITLE_ADD":
            console.log({...state,name:state.name+1});
            return {...state,name:state.name+1}
            break;
        case "USERDATA_LIST_TITLE_DEL":
            return {...state,name:state.name-1}
            break;
    
        default:
            return state
            break;
    }
​
​
    return state
}
​
export default demo

3.会发现redux的数据变了 但是页面的内容并没有改变 所以我们需要 修改组件的数据读取方式在state读取

import React, { Component } from 'react'
import Demob from "./demob.jsx"
// 1.引用store对象
import store from "../store/index.js"
export default class demo extends Component {
    // 在组件的state中读取数据
    constructor(){
        super()
        this.state={
            name:store.getState().demor.name
        }
    }
​
    fun=()=>{
        store.dispatch({type:"USERDATA_LIST_TITLE_ADD"})
    }
    funb=()=>{
        store.dispatch({type:"USERDATA_LIST_TITLE_DEL"})
    }
​
    render() {
        return (
            <div>
                使用redux存储的数据---{this.state.name}
                <div>
                    <button onClick={this.fun}>点我添加数据</button>
                    <button onClick={this.funb}>点我减少数据</button>
                </div>
                <Demob/>
            </div>
        )
    }
}
​

4.使用subscribe() 来监听store的数据变化

subscribe是一个监听器 他会监听store里面的数据 当store的数据改变的时候就会自动触发

    componentDidMount() {
        // 监听store的数据变化  
        store.subscribe(()=>{
            this.setState({
                name:store.getState().demor.name
            })
        })
    }
    

redux的流程

创建store对象 并且向store对象中注入reducer(数据与修改的动作)reducer通常都是以模块的形式存在的 我们需要使用combineReducers来吧多个reducer模块进行合并 然后把合并之后的reducer传递给store对象 在想使用的组件中直接store.getState().模块名.数据

修改 在组件中使用dispatch 调用reducer中的action.type修改任务 在任务中进行数据的修改 并且return 数据 但是数据改变了页面并不会发生改变 因为组件的render没有重新的渲染 所以 我们需要使用subscribe()来监听store对象中的数据改变 当数据改变了 我们就可以用subscribe()的监听器触发组件中的render渲染(setState()来修改state数据从而实现组件的render渲染)

react-redux

他就是一个专门为react开发的状态管理工具 它相对于redux 简化了 组件与redux的store对象之间的关联

Provider 传递store对象

connect (高阶组件) 连接 连接react与redux 从而减少彼此之间获取数据的复杂度

使用

下载: npm install --save react-redux

1.在index.js中 引用react-redux 并且结构出 provider

2.在index.js中 引用我们自己写的redux的store对象

3.开始传递

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/demo.jsx';
import reportWebVitals from './reportWebVitals';
​
​
import {Provider} from "react-redux"
import store from "./store/index.js"
​
ReactDOM.render(
  // 包裹跟组件  传递store对象
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
​
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
​

4.在那个组件中使用 就在那个组件中使用connect这个高阶组件进行连接

import React, { Component } from 'react'
// 引用连接
import {connect} from "react-redux"
​
class reactredux extends Component {
    render() {
        return (
            <div>
                {this.props.state.demor.num}
            </div>
        )
    }
}
// connect 是一个函数  只有这个函数被调用之后才是一个高阶组件
export default connect(state=>({state}))(reactredux)
​
​
​

5改

直接使用this.props.dispatch()及可修改

import React, { Component } from 'react'
// 引用连接
import {connect} from "react-redux"
​
​
class reactredux extends Component {
    add=()=>{
        // 不需要监听直接就可以进行修改
​
        this.props.dispatch({type:"ADD"})
    }
    render() {
        return (
            <div>
                {this.props.state.demor.num}
                <button onClick={this.add}>+1</button>
            </div>
        )
    }
}
// connect 是一个函数  只有这个函数被调用之后才是一个高阶组件
export default connect(state=>({state}))(reactredux)
​
​
​

生命周期钩子函数

挂载阶段:

import React, { Component } from 'react'
import Zi from "./zi.jsx"
import Zib from "./zib.jsx"
export default class fu extends Component {
    // 1.react数据初始化
    constructor(){
        super()
        console.log("react数据初始化")
    }
    // 2.准备渲染页面  还没有涉及dom
    componentWillMount() {
        console.log("准备渲染页面")
    }
    // 4.页面渲染完毕
    componentDidMount() {
        console.log("页面渲染完毕")
    }
    
    // 3.开始渲染
    render() {
        return (
            <div>
                fuffufufufufuf
                <Zi/>
                <Zib/>
            </div>
        )
    }
}
​

修改阶段

判断组件是否要更新

shouldComponentUpdate(nextprops,nextstate){ // 必须return 一个布尔值 true就是更新 false就是不更新

}

import React, { Component } from 'react'
​
export default class demo extends Component {
    componentWillReceiveProps(nextProps) {
        // 在组件接收到一个新的props的时候调用  初始化不触发    
    }
    
​
    shouldComponentUpdate(){
        // 判断组件是否要更新
    }
    componentWillUpdate(nextProps, nextState) {
        // 准备开始更新
    }
    // render() 开始更新
    componentDidUpdate(prevProps, prevState) {
        // 组件更新完毕
    }
    
    
    render() {
        return (
            <div>
                
            </div>
        )
    }
}
​

销毁阶段

componentWillUnmount() {

// 开始准备销毁

如果你的程序有一个定时器  这个定时器在页面执行的时候一直存在  那么在这个时候我们就需要在react销毁阶段去清空这个定时器

}

state----状态机

state就是在react中用来定义变量的位置

变量==状态 状态机==变量机制

之前我们不是在组件中使用 let或者var 定义过变量么为什么还要学习state?

1.定义状态数据

使用this.state={你定义变量的key:val}

import React, { Component } from 'react'
​
export default class home extends Component {
    // 他是es6类中的内容
    // 在es6中  继承的规则是  不管子类写不写constructor  在实例化的时候都会补上constructor
    // 你可以不写constructor  但是如果你写了  那么就必须在此函数中 添加一个super()调用父类的构造方法
    // 因为调用了父类的构造方法之后子类 曹会有自己的this  当时如果你不执行super()  那么子类的this都是由问题的
    constructor(){
        super()
        // 定义state
        this.state={
            text:"我是字符串",
            age:18,
            bool:true,
            arr:[111,2222,3333,4444],
            obj:{
                name:"xixi",
                sex:"男"
            }
        }
    }
    render() {
        return (
            <div>
                
            </div>
        )
    }
}
​

2.使用状态数据

使用: this.state.xxx

            <div>
                {/* 使用state的数据 */}
                {this.state.arr[2]}
            </div>

3.修改状态数据

必须使用:this.setState()来修改

import React, { Component } from 'react'
​
export default class home extends Component {
    // 他是es6类中的内容
    // 在es6中  继承的规则是  不管子类写不写constructor  在实例化的时候都会补上constructor
    // 你可以不写constructor  但是如果你写了  那么就必须在此函数中 添加一个super()调用父类的构造方法
    // 因为调用了父类的构造方法之后子类 曹会有自己的this  当时如果你不执行super()  那么子类的this都是由问题的
    constructor(){
        super()
        // 定义state
        this.state={
            text:"我是字符串",
            age:18,
            bool:true,
            arr:[111,2222,3333,4444],
            obj:{
                name:"xixi",
                sex:"男"
            }
        }
    }
​
    fun=()=>{
        // 如果你要修改state的话要使用一个方法叫  this.setState()来进行修改
        this.setState({
            // 你要修改谁:修改成什么
            text:"我被修改了"
        })
    }
    render() {
        return (
            <div>
                {/* 使用state的数据 */}
                {this.state.text}
                <button onClick={this.fun}>点我修改数据</button>
            </div>
        )
    }
}
​

当你调用了setState之后发生了什么?

1.当你调用了setState之后 他会修改state的数据 同时他还会触发组件的渲染方法(render)

2.setState是异步的

    fun=()=>{
        // setState 是异步的  所以如果在setState之后直接打印修改之后的内容是不行的
        this.setState({
            
            text:"我被修改了"
            // 所以如果你想得到修改之后的结果  那么只能在setState的第二个参数回调函数中获取
        },()=>{
            console.log(this.state.text)
        })
        
    }

函数组件怎么写state?

函数组件又叫无状态组件 默认情况下不能使用state

便利列表

import React, { Component } from 'react'
​
export default class list extends Component {
    constructor(){
        super()
        this.state={
            arr:["小明","小红","小白","小黄"]
        }
    }
    render() {
        return (
            <div>
                <ul>
                  {
                      this.state.arr.map((v,i)=>{
                          return (
                              <li key={i}>{v}</li>
                          )
                      })
                  }
                </ul>
            </div>
        )
    }
}
​

高阶组件HOC 与 反向继承

什么是HOC

react在开发中对于组件构建中不断增多 在这个过程中会有一些组件的一部分公用的功能需要被复用的时候 我们就可以把这些需要被复用的功能 封装成一个高阶组件

HOC高阶组件 就是用来封装多个组件中公用的功能

HOC 参数是一个组件 返回值还是一个组件

// 高阶组件参数是一个组件  返回值还是一个组件
import React, { Component } from 'react'
// Com是函数的形参 可以随便写 但是这个形参是需要接收一个组件的所以首字母大写
let demo=(Com)=>{
    return class index extends Component {
    render() {
        return (
            <div>
                <Com/>
                <h1>来自于2108</h1>
            </div>
        )
    }
}
​
}
​
export default demo

使用

import React, { Component } from 'react'
import demo from "../hoc/index.js"
​
class hocdemo extends Component {
    render() {
        return (
            <div>
                <h1>我是测试高阶组件的例子</h1>
                
            </div>
        )
    }
}
export default demo(hocdemo)

反向继承

高阶组件的反向继承 就是高阶组件在使用中的渲染劫持(就是在高阶组件中写一个条件渲染)

// 反向继承
​
import React, { Component } from 'react'
// 1.如果要使用反向继承  那么需要在高阶组件接收参数的时候  在多接收一个数据 就是执行条件渲染的之后他的条件
let demo=(Com,num)=>{
    return class index extends Com {
    render() {
​
        if(num>18){
            return (
                <div>
                    <Com/>
                    <h1>来自于2108</h1>
                </div>
            )
        }else{
            return (
                <div>当前页面必须18之后参能访问</div>
            )
        }
       
    }
}
​
}
​
export default demo

路由

路由的分类

react-router 他只提供了路由的核心功能 并没有提供dom操作与跳转的更多api

react-router-dom 他除了基本的核心路由功能以外 还提供了大量的跳转等辅助性的api帮助我们更好的完成路由

路由模式的分类

hashRouter 带#号 兼容性比较好 刷新不丢失

BrowerRouter 不带#号 兼容性相对较弱 上线后刷新会丢失

创建

1.下载 npm install --save react-router-dom

2.创建用来容纳路由的文件夹与文件 router文件夹 index.js文件

3.在全局配置文件中 设置路由模式

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
​
// 1.引用路由模式
import {BrowserRouter} from "react-router-dom"
​
ReactDOM.render(
  // 2设置路由模式
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);
​
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
​

4.来到router下的index中来配置路由规则与出口

<Route path="/路径" component={路径匹配的组件}/>

import React, { Component } from 'react'
// 1.引用路由页面
import Home from "../views/home.jsx"
import Phone from "../views/phone.jsx"
import User from "../views/user.jsx"
// 2.引用Route  
import {Route} from "react-router-dom"
export default class index extends Component {
    render() {
        return (
            <div>
                {/* 配置路径与出口 */}
                <Route path="/home" component={Home}/>
                <Route path="/phone" component={Phone}/>
                <Route path="/user" component={User}/>
            </div>
        )
    }
}
​

5.把router下的index。js在全局配置文件中进行配置

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
// 引用路由组件为根组件
import App from './router/index.js';
import reportWebVitals from './reportWebVitals';
​
// 1.引用路由模式
import {BrowserRouter} from "react-router-dom"
​
ReactDOM.render(
  // 2设置路由模式
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);
​
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
​

路由导航

声明式

link 只有基本的导航功能

navlink 在基本的导航功能之上 添加了一下便捷性的功能 选中类名的功能

link与navlink都有一个to属性用来设置路径

注意:navlink动态添加的类名默认是 active 但是active太危险了 因为这个类名可能会在其他地方已经使用过了 修改选中的默认类名 activeClassName="新类名" 来进行修改

<NavLink activeClassName="xiaoming" to="/home">home</NavLink>

编程式

this.props.history.push("/去哪里")

  fun=()=>{
        this.props.history.push("/user")
    }

会发现 有时候可以 有时候报错报push没有定义

出现的原因是 因为 你在不是被路由所管理的页面中使用编程式导航就会报错不是被路由所管理的页面中没有路由的history属性

如果我就是现在不是被路由所管理的页面中使用编程式导航怎么办?

解决的方式 就是让不是被路由所管理的页面也具有路由的history属性 使用withRouter这个高阶组件即可

404页面

写在最下面使用*号配置

1.引用404页面

2.在规则的最下面配置

import React, { Component } from 'react'
// 1.引用路由页面
import Home from "../views/home.jsx"
import Phone from "../views/phone.jsx"
import User from "../views/user.jsx"
import No from "../views/no.jsx"
// 2.引用Route  
import {Route,Link,NavLink} from "react-router-dom"
export default class index extends Component {
    render() {
        return (
            <div>
                <NavLink activeClassName="xiaoming" to="/home">home</NavLink>&nbsp;&nbsp;
                <NavLink activeClassName="xiaoming" to="/phone">phone</NavLink>&nbsp;&nbsp;
                <NavLink activeClassName="xiaoming" to="/user">user</NavLink>&nbsp;&nbsp;
                {/* 配置路径与出口 */}
                <Route path="/home" component={Home}/>
                <Route path="/phone" component={Phone}/>
                <Route path="/user" component={User}/>
                {/* 404页面写在最下面 */}
                <Route path="*" component={No}/>
            </div>
        )
    }
}
​

上面写完404之后会发现 404页面虽然出来了 但是其他页面每次在奇幻的时候都会显示404 原因是因为react的路由在渲染的时候 匹配到指定内容之后还会傻傻的向下继续匹配直到没有

switch 唯一匹配 唯一渲染

路由在匹配的时候匹配到内容还会向下匹配 那么我们可以使用switch这个组件来帮助我们解决上述问题

使用switch 包裹所有的路由出口

  <div>
                <NavLink activeClassName="xiaoming" to="/home">home</NavLink>&nbsp;&nbsp;
                <NavLink activeClassName="xiaoming" to="/phone">phone</NavLink>&nbsp;&nbsp;
                <NavLink activeClassName="xiaoming" to="/user">user</NavLink>&nbsp;&nbsp;
                {/* 配置路径与出口 */}
               <Switch>
                    <Route path="/home" component={Home}/>
                    <Route path="/phone" component={Phone}/>
                    <Route path="/user" component={User}/>
                    {/* 404页面写在最下面 */}
                    <Route path="*" component={No}/>
                </Switch>
            </div>

重定向 redirect

<Redirect from="从哪来" to="/去哪里”>

import React, { Component } from 'react'
// 1.引用路由页面
import Home from "../views/home.jsx"
import Phone from "../views/phone.jsx"
import User from "../views/user.jsx"
import No from "../views/no.jsx"
// 2.引用Route  
import {Route,Link,NavLink,Switch,Redirect} from "react-router-dom"
export default class index extends Component {
    render() {
        return (
            <div>
                <NavLink activeClassName="xiaoming" to="/home">home</NavLink>&nbsp;&nbsp;
                <NavLink activeClassName="xiaoming" to="/phone">phone</NavLink>&nbsp;&nbsp;
                <NavLink activeClassName="xiaoming" to="/user">user</NavLink>&nbsp;&nbsp;
                {/* 配置路径与出口 */}
               <Switch>
                    <Route path="/home" component={Home}/>
                    <Route path="/phone" component={Phone}/>
                    <Route path="/user" component={User}/>
                    {/* 配置重定向 */}
                    <Redirect from="/" to="/home"/>
                    {/* 404页面写在最下面 */}
                    <Route path="*" component={No}/>
                </Switch>
            </div>
        )
    }
}
​

精准匹配 exact

通常是在路径中/使用的 他代表完全符合这个路径规则才能匹配到

  <Redirect from="/" to="/home" exact/>

二级路由

只需要在对应的一级路由页面中使用Route来直接配置出口与规则即可

import React, { Component } from 'react'
import {Route,Link} from "react-router-dom"
import Era from "./er/era.jsx"
import Erc from "./er/erc.jsx"
import Erd from "./er/erd.jsx"
export default class phone extends Component {
    render() {
        return (
            <div>
                phone
                <hr />
                <div>
                    <Link to="/phone/era">era</Link>&nbsp;&nbsp;
                    <Link to="/phone/erc">erc</Link>&nbsp;&nbsp;
                    <Link to="/phone/erd">erd</Link>&nbsp;&nbsp;
                </div>
                <Route path="/phone/era" component={Era}/>
                <Route path="/phone/erc" component={Erc}/>
                <Route path="/phone/erd" component={Erd}/>
            </div>
        )
    }
}
​

路由传参

params方式

1.在路由规则中配置接收参数

   <Route path="/shop/:xiaoming" component={Shop}/>

2.发送

   <NavLink to="/shop/我是路由传参的参数">shop</NavLink>
​
    this.props.history.push("/shop/编程式传参")

3.接收

this.props.match.params.xxx

            <div>
                shop----{this.props.match.params.xiaoming}             
            </div>

优缺点

优点 刷新之后 参数不丢失

缺点 只能传递字符串,如果参数比较多的话 url不好看

state方式

1.发送

 <NavLink to={{pathname:"/路径",state:{传递的key:传递的val}}}>user</NavLink>
​
  <NavLink to={{pathname:"/user",state:{xiaoming:6666}}}>user</NavLink>
​
​
​
this.props.history.push({pathname:"/路径",state:{传递的key:传递的val}})

2.接收

this.props.location.state.xxx

            <div>
                user---{this.props.location.state.xiaoming}
            </div>

优缺点

优点 传参的时候 url不显示数据 并且传递的时候可以传递多条数据

缺点 刷新地址栏 会丢失

render渲染路由页面

在路由显示之前 提供一个编写业务的场所

                    <Route path="/home" render={()=>{
                        // 判断用户登录没有登录过的业务
                       return true?<Home/>:<Redirect to="/login"/>
                    }}/>
​

HOOK

HOOK是react16.8新增的一个新特性 主要就是可以让无状态组件 使用状态 生命周期 ref等内容

HOOK在类组件是无效的

useState

是HOOK中提供的最基础的内容 主要的作用就是让函数组件可以使用状态

语法:

useState() 返回的是一个数组长度为2 数组的下标0的位置 就是当前保存这个值得变量 下标1的位置就是修改这个变量的方法

let [变量 , 修改这个变量的方法 ]=useState(初始化值)

import {useState} from "react"
let Demo=()=>{
    // 定义HOOK状态
    let [text,settext]=useState("你好")
    let fun=()=>{
        // 修改的方法
        settext("我被改了")
    }
​
​
    return (
        <div>
            <h1>useState---{text}</h1>
            <button onClick={fun}>点我修改text</button>
        </div>
    )
}
export default Demo

如何使用useState定义多个值

1.你把useState多写几遍(不推荐)

2.在定义useState的时候传递一个对象

import {useState} from "react"
let Demo=()=>{
    let [data,setdata]=useState({
        name:"xixi",
        age:18,
        sex:true,
        arr:[111,2222,3333,434444]
    })
    return (
        <div>
         <h1>使用useState定义多个值----{data.age}</h1>
        </div>
    )
}
export default Demo

修改

import {useState} from "react"
let Demo=()=>{
    let [data,setdata]=useState({
        name:"xixi",
        age:18,
        sex:true,
        arr:[111,2222,3333,434444]
    })
    let fun=()=>{
        // 修改的时候注意使用...保留不修改的数据
        setdata({...data,age:666})
    }
    return (
        <div>
         <h1>使用useState定义多个值--{data.name}--{data.age}</h1>
         <button onClick={fun}>点我修改</button>
        </div>
    )
}
export default Demo

useRef

就是可以让函数组件使用ref

import {useRef} from "react"
let Demo=()=>{
    // 创建
    let u=useRef(null)
​
    let fun=()=>{
        console.log(u.current.value);
    }
    return (
        <div>
            <h1>useRef</h1>
            {/* 使用ref绑定 */}
            <input type="text" ref={u}/>
            <button onClick={fun}>点我得到input的数据</button>
        </div>
    )
}
export default Demo

useEffect

函数组件可以使用生命周期 componentDidMount 创建完 componentDidUpdate更新完毕

componentWillUnmount 销毁之前 的一个组合

import {useRef,useEffect} from "react"
let Demo=()=>{
    // 函数组件的生命周期
    useEffect(()=>{
        console.log("我是函数组件的生命周期");
    })
    return (
        <div>
            <h1>useEffect</h1>
           
        </div>
    )  
}
export default Demo

useReducer

它的主要作用就是防止 状态数据操作太多的时候 减少复杂度

语法

let [变量名,修改变量的动作]=useReducer(修改的动作,初始值)

import {useRef,useEffect,useReducer} from "react"
let Demo=()=>{
    let reducer=(state,action)=>{
        switch (action.type) {
            case "ADD":
                return state+1
                break;
            case "DEL":
                return state-1
                break;
        
            default:
                return state
                break;
        }
      
    }
    // 创建
    let [state,dispatch]=useReducer(reducer,66)
​
let add=()=>{
    dispatch({type:"ADD"})
}
let del=()=>{
    dispatch({type:"DEL"})
}
​
   
    return (
        <div>
            <h1>useReducer---{state}</h1>
            <button onClick={add}>+1</button>
            <button onClick={del}>-1</button>
           
        </div>
    )  
}
export default Demo

ref

标识组件内部的元素

react如果想使用ref 那么必须是在class组件中进行使用 函数组件由于没有实例所以不能直接使用ref

使用:

1.字符串方式(淘汰了)

2.回调函数的方式( 还勉强可以使用 )

回调函数就是在dom节点上挂载一个函数 这个函数的形参就是当前dom节点

import React, { Component } from 'react'
​
export default class funref extends Component {
    fun=()=>{
        console.log(this.demoinput.value);
    }
    render() {
        return (
            <div>
                {/* 回调函数的方式  ref接收的是一个函数
                函数的形参就是当前的dom元素
                我们把当前的形参赋值给一个变量  那么这个变量代表的就是当前的dom元素 */}
                <input type="text" ref={(el)=>{this.demoinput=el}}/>
                <button onClick={this.fun}>点我得到输入框的值</button>
            </div>
        )
    }
}
​

3.React.creatRef() (react16.3版本新增的 所以推荐使用)

1.需要创建出ref对象 使用createRef创建

  this.myRef=React.createRef()

2.创建出来的ref对象绑定到指定的DOM节点之上

3.使用

import React, { Component } from 'react'
​
export default class createRef extends Component {
    constructor(){
        super()
        // 1.创建ref对象
        this.myRef=React.createRef()
    }
    fun=()=>{
        // 3.使用
        console.log(this.myRef.current.value);
    }
​
    render() {
        return (
            <div>
                {/* 2.绑定ref */}
                <input type="text" ref={this.myRef}/>
                <button onClick={this.fun}>点我得到值</button>
            </div>
        )
    }
}
​

事件

react在事件绑定的时候 事件的名字使用小驼峰命名法

在调用函数的时候不加()不加()不加()不加()不加()

事件修饰

在react中如果想进行类似于阻止冒泡 或者阻止事件莫任性为的话 那么我们需要使用原生js的方法

阻止事件默认行为 preventDefault()

函数的实参与形参传递

因为在react中调用函数不加() 那么我们的实参写在哪里?

方式1 通过.bind的方式进行传递

import React, { Component } from 'react'
​
export default class demo extends Component {
    fun=(num,text)=>{
        console.log(num+"----"+text);
    }
    render() {
        return (
            <div>
                {/* 方式1  通过.bind的方式进行传递 */}
                <button onClick={this.fun.bind(this,"我是实参","参数2")}>点我传递实参</button>
            </div>
        )
    }
}
​

方式2 通过箭头函数调用函数进行传递

  {/* 方式2 通过箭头函数调用函数进行传递 */}
  <button onClick={()=>{this.fun("1111","22222")}}>点我传递实参2</button>

this指向修改

1.通过创建箭头函数来修改this

 fun=()=>{
        
    }

2.通过bind方式修改this

3.通过在constructor中提前绑定

import React, { Component } from 'react'
​
export default class demob extends Component {
    constructor(){
        super()
        this.state={
            text:"我是测试this指向的"
        }
​
        // 提前绑定this
       this.func=this.func.bind(this)
    }
    fun=()=>{
        this.setState({
            text:"我被修改了"
        })
    }
​
    funb=function(){
        this.setState({
            text:"我被修改了"
        })
    }
    func=function(){
        this.setState({
            text:"我被修改了"
        })
    }
    render() {
        return (
            <div>
                <h1>{this.state.text}</h1>
                <button onClick={this.fun}>通过创建箭头函数方式修改this</button>
                <button onClick={this.funb.bind(this)}>通过bind方式修改this</button>
                <button onClick={this.func}>在constructor中提前绑定this</button>
            </div>
        )
    }
}
​

Typescript

Ts 是微软开发的一个开源的编程语言 他是javascript的一个超集 本质就是对现有的javascript语法进行了更多的扩展 解决了很多js的痛点 弱类型 很难模块化等缺点

1.ts是js的一个超级集合

2.ts对js进行很多语法扩展 变成了一个强类型语言 同时页添加了很多新特性

3.ts是跨平台的 所有操作系统都可以使用

4.ts完全兼容js

开发环境

1.全局安装ts解析器

npm install -g typescript

2.查看版本 tsc -v

3 新建一个以ts结尾的文件

4.需要使用解析器解析ts 翻译成js cd到指定项目下 使用tsc 你要翻译的ts文件即可

变量

注意: 可以使用var let 来创建变量 也可以使用const创建常量

注意: let 和const的作用域同js let创建的变量名不能重名

注意: 创建变量名首字母可以使用_ 和美元$符号 但是不能包含其他特殊符号

数据类型声明机制

在创建变量的时候必须指定数据类型

let 变量名 :数据类型 = '值'

数据类型

string

number

boolean

object

array

let text:string="你好";
let number:number=666;
let sex:boolean=true;

// 数组
let arr:number[]=[111,22222,333333,44444]
let arrb:Array<number>=[111,222,3333,4444,555,6666]

// 对象
let obj:object={xxxx:"xxxx"}

不一样的

any 任意类型 在我们五噶确定变量的类型的时候 可以指定成any类型 ts会把any类型数据跳过验证 所以any还是在项目中进行少用 要保证我们项目健壮性

void 无返回值

enum 枚举 就是对一组数值起一个友好的名字 (一个命名元素的集合)

// 创建除了枚举类型
enum user {xiaoming,xiaohong="你好",xiabai="赋值"}
console.log(user.xiaoming);//默认情况下枚举类型从0开始
​
console.log(user.xiabai);//667
​
// 如果我们给枚举赋值了一个字符串 那么他以及他后面的内容都要赋值才可以

元组

已知数据类型和长度的数组

// 元组  已知长度和数量的数组
let arrb:[string,number,string]=["111",2222,"3333"]

类型别名

给现有的数据类型起个新的名字 使用type来进行别名的设置

string ----- 》xiaoming

type 新名字=原始数据类型

// 类型别名
type xiaoming=number;
​
let num:xiaoming=666

联合类型

联合类型就是可以给一个变量设置多个数据类型

// 联合类型
type xiaoming=number|string
let num:xiaoming="666"

函数

function 函数名(形参:数据类型):返回值的数据类型{

return 返回值

}

面向对象ts

我们是使用一个对象的方式来对业务进行考虑的

class 类名{
    属性:类型
    constructor(参数:类型){
        this.属性=参数
    }
    方法(){
    
    }
​
}
// 类
class User{
    // 创建属性
    name:string;
    age:number;
    constructor(text:string,num:number){
        this.name=text;
        this.age=num;
    }
    showname(){
        console.log(this.name+"----"+this.age);
        
    }
​
}
​
let demo=new User("xixi",18)
demo.showname()

面向对象

封装

本质就是一个创建含有属性和方法的容器

封装的时候 我们可以对要封装的内容设置对应的权限 方便后期继承的时候来使用

1.只读属性 readonly 使用只读描述后的属性不能被修改

2.共有的(默认值):public 公开的 谁都可以用 当前类或者子类中都是可以使用的

class User{
    // 创建属性
   public name:string;
   public age:number;
   public constructor(text:string,num:number){
        this.name=text;
        this.age=num;
    }
    public showname(){
        console.log(this.name+"----"+this.age);
        
    }
​
}
​
let demo=new User("xixi",18)
demo.showname()

3.受保护的 :protected 就是只能在当前类以及子类中使用

4.私有的 : private 只能在当前类中使用

class User{
    // 创建属性
   private name:string;
   private age:number;
   constructor(text:string,num:number){
        this.name=text;
        this.age=num;
    }
    private showname(){
        console.log(this.name+"----"+this.age);
        
    }
​
}
​
let demo=new User("xixi",18)
demo.showname()

5 静态类型 static 不用创建当前实例 就可以直接使用

class Xiaobai{
    static username="小白"
    static showname(){
        console.log("我是方法");
        
    }
}
​
console.log(Xiaobai.username)

继承性

一个对象可以使用另外一个对象中的属性和方法 使用extends关键子

class Fu{
   public name:String;
    constructor(name:string){
        this.name=name
    }
}
class Zi extends Fu{
    showname(){
        console.log(this.name)
    }
}
​
let zi=new Zi("我是参数")
zi.showname()

多态/重写

多态的前提必须是继承 如果子类的方法和父类的方法名相同了 那么子类的方法会替换父类方法中的原有内容

class Fu{
  fun(){
      console.log("我是父类的方法");
      
  }
}
class Zi extends Fu{
   fun(){
       console.log("我是子类的方法");
       
   }
}
​
let zi=new Zi()
zi.fun()

接口 -- interface

接口主要就是在定义一个类的数据结构 使用接口可以限制当前这个类的数据类型 接口是一种规范 它定义了属性和方法的规范

interface 接口名( 首字母大写并且在大写的首字母之前使用一个大写的 I 来表示 ){

数据名:数据类型

}

// 接口
interface IData{
    name:string,
    age:number,
    sex:boolean
}
​
​
let user:IData={
    name:"xixi",
    age:18,
    sex:true
}

可选属性

就是可以让定义接口有的时候其中的属性为可选状态 使用 ?来进行修饰

interface IData{
    name?:string,
    age?:number,
    sex?:boolean
}
​
​
let user:IData={
    name:"xixi",
    age:18,
    sex:true
}
// 接口在使用的过程中默认情况下  接口有几个数据  那么在使用的时候
// 就必须把这些数据都要初始化出来 少一个都不行
​
// 为了解决这个问题  我们可以使用接口的可选属性
// 就是在定义接口的时候 把定义的内容变成可需要就用不需要就不用的类型使用?来表示
let userb:IData={
    name:"xiaoming"
}

泛型

定义一个函数或者类的时候 有写情况下没有办法确定要使用的数据类型是什么(返回值,参数,属性类型) 那么这个时候就可以使用泛型来进行完成

泛型 就是值在定义函数,类的时候 不先指定具体的类型 而是在使用的时候在指定类型的一个特性

function fun(num:any):any{
    return num
}
// 从上面这个函数你会发现 类型现在不确定我们使用了any  
//  any他会关闭ts的类型验证 使用any不太推荐
​
class Con{
    name:any
    constructor(text:any){
        this.name=text
    }
}
// 从上面这个函数你会发现 类型现在不确定我们使用了any  
//  any他会关闭ts的类型验证 使用any不太推荐

使用泛型 <泛型名>

class Con<T>{
    name:T
    constructor(text:T){
        this.name=text
    }
}
// 上面这个<T>就是泛型   T就是我们随便起了个名字也可以叫其他的   设置了泛型之后
// 就可以使用T来表示类型占位

react+ts

在创建项目的时候还是使用cra脚手架 唯独在创建的时候有区别

create-react-app 项目名 --template typescript

组件

创建组件和原来一样 但是在引用的时候不加后缀名

性能优化

父组件

import React, { Component } from 'react'
import Zi from "./zi.jsx"
export default class fu extends Component {
    constructor(){
        super()
        this.state={
            arr:[
                {title:"xixi1",ck:false},
                {title:"xixi2",ck:false},
                {title:"xixi3",ck:false},
                {title:"xixi4",ck:false},
                {title:"xixi5",ck:false},
                {title:"xixi6",ck:false},
              
            ]
        }
    }
​
    fufun=(i)=>{
       
        var newarr=this.state.arr
​
        newarr[i].ck=!newarr[i].ck
​
        this.setState({
            arr:newarr
        })
    }
​
    render() {
        return (
            <div>
            
                {
                    this.state.arr.map((v,i)=>{
                        return (
                            <Zi key={i} zifun={this.fufun} title={v.title} ck={v.ck} i={i}/>
                        )
                    })
                }
            </div>
        )
    }
}
​

子组件

import React, { Component } from 'react'
​
export default class zi extends Component {
    render() {
        console.log("zizizzi")
        let {title,ck,i,zifun}=this.props
        return (
            <div>
                <input type="checkbox" onChange={zifun.bind(this,i)}/>
                <span style={{backgroundColor:ck?'red':''}}>{title}--{i}</span>
            </div>
        )
    }
}
​

通过上面的代码大家会发现控制台在一直打印执行结果 效率非常的低下 原因 是因为子组件是在父组件中循环展示如果子组件循环了1000次 那么只要父组件的render执行了 那么子组件就要重新渲染1000次

纯组件--pureComponent

纯组件 就是react性能优化最重要的方法之一 在组件发生更新的时候 组件的props或者state没有用改变 那么纯组件就不让他更新从而减少不必要的性能浪费

import React, { Component,PureComponent } from 'react'
// 使用纯组件进行性能优化
export default class zi extends PureComponent {
    render() {
        console.log("zizizzi")
        let {title,ck,i,zifun}=this.props
        return (
            <div>
                <input type="checkbox" onChange={zifun.bind(this,i)}/>
                <span style={{backgroundColor:ck?'red':''}}>{title}--{i}</span>
            </div>
        )
    }
}
​

纯组件就是react帮助我们比较了一下props与state的内存地址 看看内存地址的数据是否发生了变化 没有变化那么就不重新渲染

使用生命周期优化

import React, { Component } from 'react'
// 使用纯组件进行性能优化
export default class zi extends Component {
    // 判断组件是否要更新
    shouldComponentUpdate(nextprops,nextstate){
        // 必须return 一个布尔值      true就是更新   false就是不更新
        
        // 判断  如果新的props和旧的props相同那么这个组件就不更新
        //       如果新的props和旧的props不相同 那么这个组件就更新  
        if(nextprops.ck==this.props.ck){
            return false
        }else{
            return true
        }
     
    }
​
    render() {
        console.log("zizizzi")
        let {title,ck,i,zifun}=this.props
        return (
            <div>
                <input type="checkbox" onChange={zifun.bind(this,i)}/>
                <span style={{backgroundColor:ck?'red':''}}>{title}--{i}</span>
            </div>
        )
    }
}
​

数据请求

axios

同vue

跨域

1.在node_modules/react-scripts/config/webpackDevServer.config.js 文件中修改

2.设置代理跨域

    proxy:{
      "/api":{
          // target:"设置你要帮助跨域的地址"
          target:"http://www.weather.com.cn/",
          changeOrigin:true,
          ws:true,
          pathRewrite:{
              "^/api":""
          }
      }
  },

3.修改请求为/api

fetch

是原生的js 他是es?中新特性 给我们一个新的数据请求方式

语法:fetch("地址").then(()=>{})

语法: fetch("地址", method:"post",body:数据).then(()=>{})

语法: fetch("地址?key=val", method:"get").then(()=>{})

fetch axios jquery区别

jquery 就是基于原生xhmhttprequest对象进行数据请求

axios 也是基于原生xhmhttprequest对象进行数据请求 他是使用promise把xhr对象进行封装让其更符合当下的语法规范

fetch 不是基于xhmhttprequest对象进行数据请求 而是fetch本体就是一个js的新规范请求方式

dva

完成组件通信 基于react的一个应用级的框架 主要使用简单的api来帮助我们完成 数据之间的传递 异步数据的获取 dva=redux+redux-saga

下载与创建

全局的下载 npm install -g dva-cli

查看版本 dva -v

创建项目 cd到指定路径下 dva new 项目名 创建项目

启动 npm start

路由

按照项目默认结构自行添加

model

model就是用来放置数据与逻辑的模块 把数据和逻辑放置到这个model的模块中方便后期维护

在models文件夹下创建我们自己的模块

​
export default {
​
    namespace: 'homem',//给当前的模块起个名字
  
    state: {
        text:"我是home的数据"
    },
​
  };
  

在index。js中

import dva from 'dva';
import './index.css';
​
// 1. Initialize
const app = dva();
​
// 2. Plugins
// app.use({});
​
// 3. Model
// app.model(require('./models/example').default);
// 引用我们自己的模块
app.model(require('./models/homem.js').default);
​
// 4. Router
app.router(require('./router').default);
​
// 5. Start
app.start('#root');
​

在组件中使用数据

必须要使用connect进行连接

import React, { Component } from 'react'
// 引用connect
import {connect} from "dva" 
class home extends Component {
    render() {
        return (
            <div>
                我是组件----{this.props.state.homem.text}
            </div>
        )
    }
}
export default connect(state=>({state}))(home)

state--数据源

​
export default {
​
    namespace: 'homem',//给当前的模块起个名字
  
    state: {
        text:"我是home的数据"
    },
​
  };

reducers 修改数据的

reducers修改数据的 在他其中是一个各各的方法 每个方法就是修改数据的一个动作

   reducers:{//修改数据的
        uptext(state,payload){
            return {...state,text:"你好么么哒"}
        }
    }

组件中触发 dispatch()

  fun=()=>{
        // dva触发修改
        this.props.dispatch({
            // type:"命名空间的名字/reducers的名字"
            type:"homem/uptext"
        })
    }

effects 触发异步操作

es6 Generator

Generator主要是为了完成异步编程的 用来封装一个异步的任务 是一个异步任务的容器

特点 交出函数的执行权 让函数可以按照我们的要求走走停停

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 函数只要被调用那么就会自动执行里面的所有代码
        function fun(){
            console.log(1);
            console.log(2);
            console.log(3);
            console.log(4);
        }
        fun()
    </script>
</body>
</html>

generator语法要求

1.在声明函数的时候在哦function与函数名的中间 加一个*号 用来区分普通函数

2.yield 主要是在generator声明函数中进行使用的 他是分割暂停代码使用的

3.next() 主要就是让generator函数下一步的

    <script>
        // 函数只要被调用那么就会自动执行里面的所有代码
        function *fun(){
            console.log(1);
            yield
            console.log(2);
            console.log(3);
            yield
            console.log(4);
        }
            let gfun=fun()
            gfun.next()//下一步
            gfun.next()//下一步
            gfun.next()//下一步
    </script>

怎么进行异步操作

1.在service下新建文件夹写入如下内容

import request from '../utils/request';
​
export function query(url) {
  return request(url);
}
​

2.在组件中进行调用

import React, { Component } from 'react'
import {connect} from "dva"
import {query} from "../services/api.js"
class user extends Component {
    // 调用请求
    componentDidMount() {
        query("http://www.weather.com.cn/data/cityinfo/101320101.html").then((ok)=>{
            console.log(ok);
        })
    }
    
    render() {
        return (
            <div>
                user---{this.props.state.homem.text}
            </div>
        )
    }
}
export default connect(state=>({state}))(user)

跨域

在webpackrc文件中写入如下跨域即可

{
     "proxy":{
            "/api":{
                // target:"设置你要帮助跨域的地址"
                "target":"http://www.weather.com.cn/",
                "changeOrigin":true,
                "ws":true,
                "pathRewrite":{
                    "^/api":""
                }
            }
        }
}
​

请求数据闭环

1.组件中使用dispatch触发effects

2.使用call调用请求

3.put触发reducers修改state

import {query} from "../services/api.js"
export default {
​
    namespace: 'homem',//给当前的模块起个名字
  
    state: {//数据源
        text:"我是home的数据"
    },
​
    reducers:{//修改数据的
        uptext(state,payload){
            return {...state,text:"你好么么哒"}
        },
​
        upcity(state,payload){
            return {...state,text:payload.data.obj}
        }
    },
    effects:{
        *link({payload},{put,call}){
            // 在effect中触发异步使用call这个形参 call描述的请求可以直接返回它的请求数据
           let api= yield call(query)
           console.log(api.data.weatherinfo.city)
        //    把请求来的数据通过put交给reducers修改state
           yield put({
               type:"upcity",
               data:{
                   obj:api.data.weatherinfo.city
               }
           })
        }
    }
​
  };
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值