【前端】React快速入门+Redux状态管理

本文旨在记录react的基础内容,帮助有需要的同学快速上手,需要进一步了解描述更加稳妥和全面的信息,请查阅官方文档
官方文档点击这里进行跳转

React快速入门

先导

react框架

vue,react,angular这几种主流前端框架使用频率较高…本质还是js库。
React.js是一个用于构建用户界面的JavaScript库。它由Facebook开发并开源,被广泛应用于单页应用程序和移动应用开发中。
React采用组件化的开发方式,将用户界面拆分成独立的可重用组件。每个组件都有自己的状态(state)和属性(props),可以根据这些状态和属性来渲染出相应的UI。React使用虚拟DOM(Virtual DOM)来高效地更新和渲染界面,通过对比前后两个虚拟DOM的差异,只更新需要改变的部分,提高了性能。
React的核心思想是声明式编程,开发者只需关注界面应该是什么样子的,而不需要关心具体的更新过程。React还提供了丰富的生命周期方法和钩子函数,可以在组件不同的生命周期阶段执行相应的操作,方便开发者进行状态管理、数据处理和交互逻辑的处理。
React还具有良好的可扩展性和可组合性,可以与其他库和框架(如Redux、React Router等)无缝集成,方便构建复杂的应用程序。

react特点

  • 声明式UI:抛弃命令式的写法,更简单一些
  • 组件化:使用组件构建完整页面,降低了页面的耦合度
  • 跨平台支持:无论是小程序,还是web端,都可以使用react进行开发

react初始搭建

  1. 使用脚手架创建(create react app),打开某个你能记得住具体位置的文件夹,然后在这个文件夹下面使用指令创建react项目

    npx create-react-app react-basic(项目名称)
    

    创建成功以后,生成结果如下
    【前端】React快速入门+Redux状态管理_第1张图片

    (注意一个问题,使用脚手架创建react项目的时候,不允许使用驼峰命名法,只允许使用小写字母+连字符链接)

    创建成功后则会提示,并且产生一个命名好的文件夹,这就是所有的react文件的所在地点
    【前端】React快速入门+Redux状态管理_第2张图片

    接下来启动可以使用指令:

    yarn start    或者 npm start
    

等待大约30秒以后,出现这个web界面即为成功,这个时刻react服务会占据你的3000端口(默认)
【前端】React快速入门+Redux状态管理_第3张图片

react的项目资源

初始创建出来的react文件应该是这样子的
【前端】React快速入门+Redux状态管理_第4张图片

其中,入口文件为index.js,内部结构如下,和vue中挂载的原理很接近

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';                        
import reportWebVitals from './reportWebVitals';
//获取跟组件dom元素,并且根据这个元素创建节点
const root = ReactDOM.createRoot(document.getElementById('root'));
//然后把渲染挂载到这个dom节点上
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// 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();

  • react为框架的核心包
  • reactdom是专门做渲染的包
  • App是根组件
  • index.css是全局的框架

另外去掉严格模式节点: 18以后简易这样子处理会好一些
在这里插入图片描述

  • 另外注意,linux下安装react是一样的逻辑和处理方法,难能可贵的一点

jsx

jsx是个啥

jsx就是JavaScriptHTML,在js中去书写html标签,文件名后缀可以是js文件,也可以是jsx文件

//举个例子
function App() {
  return (
    
); }

优势:语法类似html,可以使用js的可编程性创建html,综合了以上两种的优点

注意:jsx是js语法的扩展,本身浏览器是不理解jsx语法的,在底层中react中有一个jsx的包帮助转化成js语法

jsx的具体语法

一些使用的案例

注意这些案例只是一些实际应用到jsx的情况,不是什么官方语法!可以简单学着写一写,理解为主

和模板语法很像 大致写法就是 {js的表达式} ,注意这里是表达式!

表达式:说白了表达式的意思就是数值,最简单的判断方法就是看能不能输出到控制台
在这里插入图片描述

列表渲染

比如我们想要实现一个数组的时候,可以通过map在遍历过程中创建标签,举个例子差不多是这样的

【前端】React快速入门+Redux状态管理_第5张图片

总结起来就是在js中写html自由度较高,但是想在html标签中写js表达式,要在中括号里写

并且这个规律是可以嵌套的

如何判断是不是表达式:能return,或者说能打印的

另外在jsx语法中,可以作为数值的东西,包括html标签捏

条件渲染

或者说选择性渲染,可以使用三元运算符和逻辑运算符,或者像这样手写if

例如这个列表中,我们对于id大于15的人进行显示

【前端】React快速入门+Redux状态管理_第6张图片

总之就是在html标签内部写js表达式的时候要加上{}

或者说满足另一个需求,符合条件才渲染(这个时候想要显示的html标签可以使用null来代替)

【前端】React快速入门+Redux状态管理_第7张图片

对于一些比较复杂,而且方向比较多的分支,建议将其抽象出来作为一个方法

【前端】React快速入门+Redux状态管理_第8张图片
在实际应用中,为了防止某些标签发生响应不及时,或者无法动态更新自己的属性的时候,我们还有一种肥肠丑陋但是有效的写法

{ isShow && 
利用前面的布尔数值来判断这个是否显示
}

css样式处理

使用jsp语法可以对style实现样式的处理…不过这个玩意好像在js里也是有的

样式一共有两种控制方法:内联控制,以及第二种使用类名控制

在这里插入图片描述

很简单,并且第一种的第一个{}内部可以换成一个符合style规范的对象

另外类名可以动态控制,也可以有多个

注意事项

  • jsx必须存在一个根节点,可以使用<>(幽灵节点替代)

【前端】React快速入门+Redux状态管理_第9张图片

是不被允许的,必须有一个总领的标签元素

  • jsx支持换行,如果换行最好使用()进行包裹,这样子代码可读性会更好一些

组件

组件是什么

组件化开发在vue中也是经常使用的,每个组件都是独立的,并且组件之间也可以进行通信,有利于复用和维护.

组件的两种类型以及渲染

  • 函数组件
  • 类组件

函数组件的创建和渲染

函数类组件的创建其实就是一个函数,返回值为一个div标签

function Hello(){
    return 
hello
}

函数式组件的使用也是直接在父组件中使用

function App() {
  return (
    
);}
  • 函数组件的要求是名称必须大写,不仅仅是语言规范,react内部也是通过标签的首字母判断这是html标签还是组件

类组件的创建和渲染

类组件的创建比较模板化,首先是继承react.component,然后是render必须有返回值

class HelloComponent extends React.Component{
    render(){
        return <div>hello this is a classComponent</div>
    }
}
  • 和函数组件一样,类组件名称首字母要大写
  • 继承自React.Component类
  • 要导入对应的包"React"

事件绑定

  • 如何绑定事件

on+(对应的事件) = {触发的函数}

以下是一个比较标准的类组件中绑定事件的写法

class HelloComponent extends React.Component{
    f1=()=>{
        console.log("回调函数已经启动")
    }
    render(){
        return <div onClick={this.f1}>hello this is a classComponent</div>
    }
}
  • 事件对象

想要获取事件对象本身,例如在上面这个地方获取到"点击事件"的具体信息

只需要在事件绑定的回调函数里面,加上参数e

   f1=( e )=>{
        console.log("事件的具体信息为",e)
    }
    render(){
        return 
hello this is a classComponent
}

按照上面的例子修改,则事件具体信息如下

在这里插入图片描述

得到事件以后,我们可以进行一些操作**:比如阻止默认跳转,阻止冒泡,懒加载等等**

  • 事件绑定的函数传入额外参数

有些时候想要传入的是参数,或者说想要传入事件和参数两种argument,就用回调函数先把参数是一个事件这种事情,确定下来

    f1=(e,num)=>{
        console.log("事件为:",e,"传入的参数为",num)
    }
    render(){
        return 
this.f1(e,12)}>hello this is a classComponent
} /*解释一下为什么这样子写 首先是使用回调函数的形式,是为了第一步先行接收事件对象,后面即使在传入参数的时候,也不会把这个当成普通参数看待 如果是一开始就一同接收,只会当成一个普通的参数*/

组件状态(类组件为主)

  • 状态的定义

状态的定义其实很简单,就是一个在类组件中,名为state的对象
在这里插入图片描述
在vue里面,我们可以对某个固定属性绑定v-model标签,这个标签可以让data和数据产生双向的响应的动态绑定.并且vue本身主打就是响应式.但是react有所不同,react的响应式效果没有vue那么强大,但是更加专一.
写在状态中的数据,是可以被响应式检测和监听的

在这个state中定义的所有属性,都是一个状态,其实这部分很类似vue中的data

  • 组件的修改

组件内部数据的修改用到的方法比较粗暴,不允许我们直接去this.state.name=''xxxxx’这样修改

但是我们可以修改整个state(锁喉)

【前端】React快速入门+Redux状态管理_第10张图片

使用整个setState(对象)函数,在参数中填写一个新的state对象

(不然你以为它为什么叫setState…)

* 一些需要注意的问题
1.编写组件其实就是编写一个原生类/函数,定义状态必须使用state整个固定名称
2.修改state中的任何属性都不能通过直接赋值,只能通过setState方法,这个方法来自于继承

3.以及一些关于this的问题
//对象调用自己的方法,this就是当前的对象
//单独的全局函数调用,指向的是undefined(前提是严格模式,非严格模式(sloppy)下为自身)
//箭头函数没有自己的this,指向的是父上下文的this
//作为监听器的回调函数,指向的是监听的dom元素

4.一个老版本问题
以前的话,如果调用函数的时候不加上括号(),会让函数无法获取绑定到this属性
但是es6版本后更新了这个毛病,使用箭头函数可以自动绑定this

一些修改的小技巧:解构语法

用react做表单处理

目标:使用受控组件获取表单的数值

方法:受控组件,非受控组件

  • 受控组件:举个例子,input框自己的属性被react的状态控制

手动实现类似v-model双向数据绑定的操作

{//react中没有类似的语法糖,只能手动实现
                        const  str=document.querySelector('.inputLog').value
                        this.setState({
                            name:this.state.name,
                            valueOfBlock:str
                        })
                    } }/>

这种是稍微原始一点的操作(一看就是刚学完es6)

首先获取到当前dom元素的value数值,然后根据这个value数值修改状态(这也是v-model的使用方法)

  • 至于受控组件

则是数值不被state所控制,直接通过dom元素进行控制

组件之间通信

组件之间的通信可以分为以下情况和处理方法,由于函数和类组件的不同,可能还有不同的处理方式

  • 父子通信
    • 父传子
    • 子传父
  • 兄弟通信
  • 其他通信

父子通信

父传子通信

父亲向子元素传递数据的方法和vue有些相似,但是原理8一样

  • 父组件要传递的元素写在自己的state状态中
  • 子组件接收数据,在自己的标签中用自定义名称接收
  • 子组件使用数据的时候分两种情况
    • 子组件为函数类组件的时候,需要在函数声明加上一个参数,这样会传入一个对象,对象内部就包含了父组件传递的数据(用的是自己定义的名称)
    • 子组件为类组件的时候,可以在子组件内部直接使用this.props.xxx

class Father extends React.Component{ 
    state={   name:'this is father`s data'  }        父组件数据
    render() {
        return (
父组件中调用子组件
) } } class SonOfClass extends React.Component{ 类子组件 render() { return (
类组件接收数据的方法为{this.props.msg} 类子组件接收
) } } function SonOfFunction(props) { 函数子组件 return (
函数组件接收数据的方法为{props.msg} 函数子组件接收(注意上面还有个函数)
) }
子传父通信

子传父通信的原理为:子组件调用父组件传递过来的函数,并且把想要传递的数据当成函数的实参传入

父组件仍然是通过给子组件上标签的方法,给子组件传递一个函数对象

//父组件中的情况
    met1=(num)=>{
       console.log('子组件传递过来的消息为',num)//打印所有的方法
    }
    render() {
        return (
//传入方法仍然是可以自定义名称的
) }

子组件可能会遇到一些问题,下面直接给出两种常用写法,再说为什么要这样

        

子组件调用的时候传入一些数据,然后父组件中就可以利用`这些数据修改点东西了

这里解释这两个button为什么要这样子写,因为我们要传入参数,对一个函数传入参数这种表达已经不符合"js表达式"

我们只有让返回值是一个传入参数的函数

  • 第一种就是bind,众所周知,bind的作用在原生js中是绑定上下文对象,并且返回一个新的函数
  • 第二种是使用箭头函数,返回值进行处理

兄弟通信

兄弟组件的通信,综合了以上两种方式,使用一个通过的父组件

A传递到Father组件,然后再由Father组件传递给B

这里不加解释了

其他通信

不是兄弟也不是父子的时候,通信方式就很抽象了

其实也不是很抽象,用到Provider和Consumer两个对象,这两个对象是在Context对象下的

  • 第一步,先创建Context,然后从里面得到两个对象Provider和Consumer

    (为了省点力气,这里我们直接使用解构语法)

在这里插入图片描述

(注意这里的defaultValue是默认数值,没啥影响)

通过解构语法直接得到传输对象

  • 第二步,用****包裹父组件的根组件,然后在value属性中,写下自己想要传输的数据

在这里插入图片描述

  • 第三步,在想要用到数据的地方,按照如下方法(固定格式),使进行传输数据

在这里插入图片描述

(注意Consumer不用包裹任何东西, 按照这个,里面写个jsx语法包裹回调函数就行力

这种传递数据的方法其实是父传子的延申,爷传孙罢

组件生命周期

首先注意,只有类组件由生命周期这个东西,虽然函数组件也存在更新和副作用的机制,但是本质上还是不一样的

组件的声明周期一共包括几个概念:

  • 三个阶段:挂载/创建,更新,卸载
  • 五个常用钩子函数
  • 两个阶段:render commit

有一张图画的挺清晰明白的(模仿着画的)

【前端】React快速入门+Redux状态管理_第11张图片

每个阶段都是由上至下进行经历的,在此期间会触发钩子函数方便访问

挂载阶段:
constructor:创建组件的时候最先执行,初始化state,创建ref,使用bind绑定什么的
(但是前两种是过时写法了,现在不怎么用)
render:每次组件渲染(包括初次创建和每次更新)都会触发,负责渲染ui(这里不能用this)
componentDidMount:组件挂载并且完成渲染以后执行一次,这时候可以进行一些网络请求和dom操作
更新阶段
render:同上
componentDidUpdate:更新结束触发,可以直接获取dom元素
卸载阶段
componentWillUnMount:8用解释了吧

注意两点:

  • render阶段是创建+渲染,在这个阶段是不允许我们调用this这个指向的
  • 另外在render和componentDidUpdate中,都不能使用setState这种更新函数,因为更新会造成这些钩子的死循环调用

钩子函数的使用方法举例:

class Life extends React.Component{
    constructor() {
       super();
       console.log("construct")
    }
    componentDidMount() {
        console.log("挂载结束")
    }
    render() {
        return (
            <div>
            </div>
        )
    }
}

关于hook

hook的本质也是一系列钩子函数,这些工资函数让函数组件也拥有了state

hook这个i能在函数组件中使用,解决了复用和class过于笨重的问题

  • 常用函数:useState

该钩子函数的返回值为一个数组,数组的第一项和第二项,分别为数据和修改数据的方法

该函数输入参数为这个数据的初始数值

每次使用这个函数,都可以得到一个数据和对应的方法,允许多次调用获得多个state属性

const [count,setCount]=useState(0)     //直接使用解构语法获得前面两项
//count:数据状态
//setCount(新数据):整体修改数据

这其中,setCount的本质和前面类组件的setState原理是一样的,都是用新数值替换旧数值,所以在需要一些复杂逻辑的时候,可以这样子写

//对于setCount(姑且这么称呼)这种函数,有一种情况为用回调函数作为参数
  setCount( ()=>{
     //编写运算逻辑.........
     return   //但是最后还是要返回东西
  })
//这样子帮助我们解决了一些复杂问题,其实本质还没变....

关于具体的使用

function TestHook_useStated(){
    //每一个state属性都要重新创建
    const [count,setCount]=useState(0)
    const [count2,setCount2]=useState(100)
    const [count3,setCount3]=useState({age:12,name:'张三'})
    //得到的修改数值的函数,参数就是新的state,本质和setState一样,用新数替换旧数值
    return (
        <>
            <div onClick={()=>setCount(count+1)}>{count}</div>
            <div onClick={()=>setCount2(count2-1)}>{count2}</div>
            <div onClick={()=>setCount3({age:count3.age+1,name:'李四'})}>{count3.age},{count3.name}</div>
        </>
   )
}
  • 常用函数useEffect

首先,有必要说明一下,什么是副作用

副作用:对于react来说,主作用就是根据内部数据渲染ui,除了主作用,剩下都是副作用,

比如dom操作,发送ajax请求,以及一些webapi的调用
useEffect就是干这个用的,把副作用放进这里面,维护函数的纯净

  • useEffect函数的执行时机是可以控制的,在默认条件下,执行是发生在任何一次更新(包括构建)

    //但是可以通过依赖项目,控制时机
    //useEffect有两个参数,一个参数为回调函数,另一个参数为监听数组
    //1.默认情况下不加整个参数,则每次更新/重构都会执行     useEffect(()=>{})
    //2.空数组,代表只执行一次                          useEffect(()=>{},[])
    //3,数组中的监听元素如果发生变化,则执行一次+初始化一次  useEffect(()=>{},[A,B,C])
    
  • useEffect对于一些副作用来说,是要进行消除的,函数内部提供了析构的方法,就是返回一个回调函数

    useEffect(()=>{
        return ()=>{
            //关于清理的逻辑
        }
    },[]) //这种就是只有初始化的时候执行一次的情况
    
  • 关于具体的使用案例如下

    function TestHook_useEffect(){
        useEffect(()=>{
            console.log("修改")
            document.querySelector('title').innerHTML=1;
            return ()=>{
                //关于清理的逻辑
            }
        },[]) //这种就是只有初始化的时候执行一次的情况
        return(
            
    console.log("修改")}> 点我测试
    ) }

路由

首先路由不是原生react中的内容,和vuex,redux一样,需要另外单独安装
(另外注意,v6版本是router的一个分水岭,我这里写的都是基于router6的内容)

下载指令为

yarn add react-router-dom@6

然后导入几个最重要的包

import {BrowserRouter, Link, Routes, Route} from 'react-router-dom'

就可以放心使用了

路由的核心组件

路由最重要的组件为四个

  • Router(分为哈希式路由HashRouter和浏览器路由BrowersRouter)
  • Link
  • Routes
  • Route

Router:最根本的展示区域,所有和路由相关的东西都应该包裹在内部

Link: 跳转路由的位置,需要在内部的to属性中写明将要跳转的地址,会在最后的h5界面中被变化为a标签

Routes:这个名字怪怪的,叫RouteContainer更好一些…

Route:路由组件,里面的path属性为开放端口,element属性则为具体的组件

路由会根据条件,从中跳转到合适的路由组件并且显示

举个例子:

                
                    首页
                    关于
                    
                        }/>
                        }/>
                    
                

路由之间传递参数

路由传递参数有两种格式

  • 第一种,使用Params传递

    在父组件中,url中给传递数据的格式为如下格式

    to中直接传递参数,path中使用占位符的方式获取参数

     首页
    
     }/>
    

​ 子组件中,使用useParams获取一个对象

     ```
      const params=useParams()
         return(
             
输出结果为:{params.id}
) ```
  • 第二种,使用SearchParams传递

    在父组件中,url中给传递数据的格式为如下格式

    to中通过url的get格式传递参数

     首页
    

​ 子组件中,使用useParams获取一个数组,数组的第一个是一个解构类似map的对象

const [params]=useSearchParams()
    return(
        
输出结果为:{params.get("id")}
)

至于嵌套路由,这里直接举个例子

import { BrowserRouter as Router, Link, Route } from 'react-router-dom';

function ParentComponent() {
  return (
    

父级组件内容

  • 子路由1
  • 子路由2
  • {/* 子级路由规则 */}
    ); } function ChildComponent1() { return

    子组件1内容

    ; } function ChildComponent2() { return

    子组件2内容

    ; } function App() { return ( {/* 路由规则和组件的对应关系 */} ); }

    编程式导航

    编程式导航,其实就是我们尝试使用代码逻辑去控制路由的跳转,而不是link

    使用编程导航,主要一下两步骤

    1. 通过useNavigate获取一个跳转函数
    2. 调用跳转函数,输入路由和其他依赖作为参数,完成路由跳转

    举个例子

        const navigage=useNavigate()
        const goPage=function (){
            navigage('/page',{replace:true})
        }
        return(
            
    ) //跳转函数里面自带两个参数 //里面两个参数,第一个参数要跳转到的路由地址 //第二个参数为一些配置信息的对象,比如replace:true 为不加入历史路径 //注意以上实现只能在组件中使用,换句话说就是在这个标签里面(就是哪两种核心组件) //所以一般引入一个新的组件,比如routerLink(自己随便去起个名字吧)用来管理固有的信息和逻辑 //{最好在根组件外部创建}

    #补充:关于状态管理工具

    React笔记2

    redux:集中状态管理,类似Java中的vuex

    redux

    redux的本体其实是一个状态管理工具,js的状态容器,在react中,通常用来存储一些通用的,需要响应化的属性

    npm install --save redux
    

    绑定react

    npm install --save react-redux
    

    创建开发者工具

    store是根据reducer方法创建的

    集中状态管理最终抽象一下可以理解为这样子

    • 修改状态的方法:store发送action对象
    • 获得状态的方法:store.getState()函数即可得到state对象

    【前端】React快速入门+Redux状态管理_第12张图片

    react-redux

    redux本身支持很多东西,包括原生js,redux官方出品,专门用于react的绑定库,方便一些操作

    • porvider:让store能全局化
    • connect:让组件和store进行关联

    基本使用

    Provider:

    包裹在根组件上(注意一定是根组件上),并且在这里往下传递一个store属性,让下面都能访问到store

    const store=react.createStore()
    root.render(
        
            
            
        
    );
    

    这样传递一个很显著的特点是,后面的组件都不需要再手动调用store来进行dispatch或者和getState

    并且结合后面的两个方法,可以让发送action的方法,和state都整合进props里面

    connect的参数:

    mapStateToProps(state,ownProps),监听store是否被修改,并且把store中的state绑定到props中

    mapDispatchToProps(dispatch,ownProps),把action绑定到props中

    (上面两个函数的第二个参数可以不用写,因为把你需要的东西加入返回值里面,就会自动绑定到你的props中)

    • mapDispatchToProps:作用是将Action的构建方法以返回值的形式封装进props中,举个例子,主要用在发出修改的主页上面

      //使用了这个绑定该方法以后,就会把你需要的东西绑定进props中
      const misDispatchToProps=(dispatch)=>{
          return{
              sentAct:()=>{                     发送action对象的方法
                  dispatch({                    由于在根组件上已经提供了一个store,所以这里直接可以使用dispatch
                      type:'send',
                      value:a
                  })
                  a++
              }
          }
      }
      //首页组件
      class ComA extends React.Component{
          handleClick=()=>{
              //发送action
              this.props.sentAct();
          }
         render(){
             return(
                 
      ) } } //增强这个对象 export default connect(null,misDispatchToProps)(ComA)
    • mapStateToProps:**作用是将Store中更新的state接受下来,**并且以返回值的形式保存在props中,主要用在接收组件上面

      //会把接收到的,被修改以后的state保存在props中
      const mapStateToProps=(state)=>{
          console.log('comb',state)
          return state
      }
      
      //首页组件
      class Comb extends React.Component{
          sta=this.props
          render() {
              return(
                  
      显示数据{this.props.value}
      ) } } //增强这个对象 export default connect(mapStateToProps,null)(Comb)

    大致的逻辑结构可以为:

    【前端】React快速入门+Redux状态管理_第13张图片

    某种角度上来说,可以认为props托管了一部分本该有state发出的动作

    你可能感兴趣的:(前端,前端,react.js,前端框架)