20230516----重返学习-react基础-业务开发思路

45 篇文章 0 订阅
8 篇文章 0 订阅

day-071-seventy-one-20230516-react基础-业务开发思路

react基础

  1. MVVM(Vue) 与 MVC(React)

    • MVVM: Model View ViewModel,双向数据驱动。
      • 基本构成:
        • Model:数据层
        • View:视图层
        • ViewModel:视图模型,Vue主要实现的。
    • MVC: Model View Controller,单向数据驱动。
      • 基本构成:
        • Model:数据层。
        • View:视图层。
        • Controller:控制层。
      • 学习这两类框架的基本思路:
        • 要学会如何构建数据与状态,以及修改状态的方法。
          • 例如:setState、useState…
        • 当基于特定的方法修改状态后,要学会通知视图更新。
          • Vue中会对对象的每一项进行get/set劫持
            • Vue2:Object.defineProperty
            • Vue3:Proxy
            • this.age=17 => 修改了对象中的某个属性 => 触发set劫持函数 => 通知视图更新。
            • 所以数据就有了响应式与非响应式数据的区别。
              • 响应式:经过get与set劫持的对象及对象属性。
              • 非响应式:没有经过get与set劫持的对象及对象属性。
          • React 并没有对数据进行特殊的处理。
            • this.state.age=17 => 只是单纯的修改值
            • this.setState({age:18}) => 只有基于特定的方法,进行修改状态值,才会让视图更新。
          • React的MVC框架中,实现了数据驱动视图渲染,也就是M->V。
            • 也就是说基本上要放弃DOM的手动更改,DOM更新需要数据进行修改之后的由框架来完成。
              • 实际操作中,就是返回一个jsx元素。
                • jsx元素就是一个数据。
                • 至于jsx元素如何转变成页面上的DOM结构,就交由React框架来做处理了。
        • 要学会如何构建视图。
          • 主要构建视图的方式:
            • Vue中是基于主要的template标签语法 与 jsx语法构建视图的。
            • React中构建视图的语法是:jsx。
          • 不论是Vue还是React,构建的视图都有一套编译机制:
            • VirtualDOM(虚拟DOM) -> DOM-diff -> 真实DOM。
        • 如果视图中的表单元素内容发生改变:
          • Vue会基于v-model指令,自动监听表单内容的变化,然后把对应的状态值进行自动更改,所以Vue是双向驱动的框架。
            • 具有视图驱动数据更新的机制,即V->M。
            • 也就是说,表单元素数据的更新,是Vue内部实现的。
              • 而vue的双向数据绑定,大多是需要使用表单元素才能驱动数据更新。
          • React默认没有实现视图驱动数据,需要开发者手动对表单元素进行事件绑定和监听,手动去修改对应的状态,所以React被称为单向数据驱动的框架。
            • 这个也就是说,主要通过对表单元素的处理监听,也大多可以双向绑定。只是这一步,需要让开发者自己去完成。
    • 具体到技术选型,主要看团队氛围与编程喜好,以及技术负责人。一般实际开发中的性能都差不多。
      • vue更简单些,招人也更容易。
      • React上限高些,更灵活。
  2. 关于版本问题。

    • Vue框架,涉及现代开发,一般都依赖于脚手架@vue/cli或vite。
      • Vue2 主流版本,目前2023年中国用得最多。
        • 全家桶:
          • @vue/cli – 脚手架。
          • Vue2 – Vue核心。
            • 做双向数据绑定。
          • Vuex3 – 做全局状态管理。
          • VueRouter3 – 做页面路由跳转。
            • 根据路由显示与隐藏某些组件的。
          • UI框架:ElementUI与Antdv1或vant2或iview。
      • Vue3 技术与业务新的趋势。
        • 全家桶:
          • vite – 脚手架。
          • Vue3 – Vue核心。
            • 做双向数据绑定。
          • Pinia 或 Vuex4 – 做全局状态管理。
            • 项目中主要用Pinia。
          • VueRouter4 – 做页面路由跳转。
            • 根据路由显示与隐藏某些组件的。
          • UI框架:ElementPlus或Antdv或vant3。
          • TypeScript – 加强JavaScript语言功能。
    • React框架
      • 原生方案:
        • create-react-app 或 vite — 脚手架。
          • 主要用的create-react-app。
        • React18与React16 — React核心。
          • 15版本已经老了,React16才添加hook语法。
          • React17基本上保持React16的特点。
          • 主要学的是React18,因为React16上有的东西,它基本上都支持。
        • redux 或 mobx 或 zustand – 做全局状态管理。
          • 主要用的redux。
        • react-router-dom5 或 react-router-dom6 — 页面渲染。
          • 与React每个版本都有些兼容,两个都要学。
        • Antd 或 AntdMobile — UI框架组件库。
          • Antd – PC端。
          • AntdMobile – 移动端。
        • TypeScript – 加强JavaScript语言功能。
      • 淘系React方案:
        • umi
        • antdpro
          • 核心:
            • redux或redux-saga。
            • react-router-dom5。
            • dva – 数据流方案。
    • 小程序开发
      • 原生小程序开发。
      • Vue:uni-app。
      • React:taro。
    • NativeApp开发
      • 原生开发。
      • Vue:uni-app。
      • React:react-native。
      • flutter:Dart语言。
    • 项目应用级体系(主流):
      • 全栈工程师体系2023年
        • Node – 语言核心。
        • Express(或Koa2、Egg) — web服务器。
          • 主要用的Express。
        • Mongodb(或MySQL、SQLServer…) — 数据库。
          • 主要用的Mongodb。
        • Linux(Nginx、Docker) — 服务器。
          • Linux是操作系统,学命令行。
          • Nginx是代理服务器,类似于前端的web服务器。
          • Docker是容器管理,不太清楚。
        • nuxt.js/next.js — SSR渲染。
          • nuxt.js 是Vue框架。
          • next.js 是React框架。
      • 微前端
      • 低代码
      • 可视化
        • 2D:canvas(ECharts)
        • 3D:webGL(three.js)
      • Web3(区块链)
      • Electron框架 – PC桌面端
  3. jsx语法

    • jsx:JavaScript and xml (html)
    • 为了让vscode支持jsx语法,让其可以有提示、可以格式化等。
      • 故而把需要构架视图的js文件,其后缀名改为.jsx

        <div>//没有提示`</div>`;
        
        <div></div>//会有`</div>`的提示;
        
      • 可以把每一个.jsx理解为一个单文件组件。

        • 可以构建视图。
      • .jsx的文件,在webpack打包的时候,也是按照js的方式处理。

      • 把所有的视图(内容)编译后,都放在#root的容器中渲染。

        • React18是这样写的。

          import React from 'react'
          import ReactDOM from 'react-dom/client'//想构造web页面,就引入'react-dom/client'。
          // ReactDOM.createRoot()// 创建一个根节点。
          const root = ReactDOM.createRoot(document.getElementById('root'))
          // 通过根节点中的render把jsx中的DOM对象放到根节点中。
          root.render(
            <div>
              珠峰培训
            </div>
          )
          
        • 在React16中,这部分是这样操作的:

          import React from 'react'
          import ReactDOM from 'react-dom/client'//想构造web页面,就引入'react-dom/client'。
          
          ReactDOM.render(
            <div>
                珠峰培训
            </div>,
            document.getElementById('root')
          )
          
    1. 在jsx语法中,我们基于{}大胡子语法绑定JavaScript表达式。

      • {}也简称胡子语法。
      • JavaScript表达式:执行有结果(返回值)的操作。
        • 变量 {title}

        • {"字符串值"}

        • 数学运算 {1+1}

        • 判断操作 {1===1?"ok":"no"}

          • 只能使用三元运算符。

            • if/else、seitch/case不算表达式。
              • 它们算操作语句,但不算JavaScript表达式。
            import React from "react";
            import ReactDOM from "react-dom/client";
            // let isExist = true;
            let isExist = false;
            const root = ReactDOM.createRoot(document.getElementById("root"));
            root.render(
              <div>
                {isExist ? <button>按钮</button> : null}
              </div>
            )
            
        • 循环操作 {arr.map(item=>{return item*10})}

          • 如: {[1,2,3].map(item=>{return item*10})}

            {
              arr.map((item,index)=>{
                return <li key={index}> //循环创建的元素,要设置唯一的key属性值
                    {item}
                </li>
              })
            }
            
          • 不能直接使用for循环等循环语句。

            • for、while、for-in等循环,不算JavaScript表达式。
          • 一般使用数组中的map语法或filter等方法。

            import React from "react";
            import ReactDOM from "react-dom/client";
            let title = `fang-react-title`;
            let arr = ["选项1", "选项2", "选项3"];
            const root = ReactDOM.createRoot(document.getElementById("root"));
            root.render(
              <div>
                <h2>
                  {title} {100}{" "}
                </h2>
                <ul>
                  {
                    //arr:[<li key={0}>{选项1}</li>,...]
                    arr.map((item, index) => {
                      return <li key={index}>{item}</li>; //循环创建的元素,要设置唯一的key属性值。
                    })
                  }
                  <li>选项2</li>
                </ul>
              </div>
            );
            
        • 函数调用

          • 包括自执行函数

            <li>{(() => 15)()}</li>
            
      • 在胡子语法中,嵌入不同数据类型的值,最后渲染的结果是不同的。
        • 原始值类型中:除了数字字符串会直接渲染出来,其余的值,最后渲染的结果都是空-不显示。
        • 对象数据类型:
          • 数组对象:不会转成字符串再渲染,而是内部会把数组中的每一项都单独拿出来渲染。
          • 函数对象:期望我们是基于<Component>组件语法这种方式调用函数组件。
          • 剩下的大部分对象,是不允许直接在胡子语法中渲染的!
            • 排除两种特殊情况:

              • 给元素设置style行内样式!

                let styleObject = { color: "red" };
                <p style={styleObject}>这是一个段落</p>
                
                • 给元素标签设置style属性,只能使用对象语法。

                  <p style="color: red">这是一个段落</p>//会报错。
                  
              • 给元素设置style行内样式,需要使用对象的。

                <p style={{ color: "red" }}>这是一个段落</p>
                
            • 如果对象是jsx元素对象(VirtualDOM),是可以直接渲染的。

              <p >{<a>8888</a>}</p>
              
              <p>{true ? <a>8888</a> : null}</p>
              
    2. 给元素/组件设置属性

      • 如果属性值是一个字符串,直接正常设置即可

        <div name="box"></div>
        
      • 其余情况:非字符串,此时基于{}嵌套绑定即可,即直接用胡子语法包起来。

        let theName = "box"
        <Component name={theName}></Component>
        
        • 例如:
          • 把变量的值作为属性值。

            let theName = "box"
            <Component name={theName}></Component>
            
          • 传递的属性值是其它类型的。

            <Component index={5}></Component>
            
      • 特殊情况:

        1. 给元素设置的class要改为className。

          <div className="the-class-1">the-class-1</div>
          
          • 不必也没关系,依旧会正常渲染,但会报错。

            <div class="the-class-2">the-class-2</div>//报错 Warning: Invalid DOM property `class`.不过依旧可以正常渲染。
            
        2. 给元素设置的style,要求其属性值必须是一个对象。

          let styleObject = { color: "red" }
          <p style={styleObject}>这是一个段落</p>
          
          <p style={{ color: "red" }}>这是一个段落</p>
          
          <p style="color: red">这是一个段落</p>//会报错。
          
      let num = 10
      <Component name="box" x={num} y={0} className="box" style={样式对象}/>
      
    3. 每个视图-无论大视图还是小视图,都只能设置一个根节点。

      • 小视图如果想要设置成多个根节点,则要用数组包起来。

        //数组包起来。
          <div>
            <div>1</div>
            <div>2</div>
            {[1,2,3].map(item=><p key={item}>{item}</p>)}//map返回的就是一个数组包起来一群子元素的根节点集合。
          </div>
        
        //只返回一个根节点。
        let root = ReactDOM.createRoot(document.getElementById("root"));
        root.render(
          <div>
            <div>1</div>
            <div>2</div>
            {[1, 2, 3].map((item) => {
              return <p key={item}>{item}</p>; //正常
            })}
          </div>
        );
        
      • 基于map循环的时候,每一轮循环产生的上下文,都算是一个小的视图,也不允许出现多个根节点。

        //map中返回多个根节点,报错。
        let root = ReactDOM.createRoot(document.getElementById("root"));
        root.render(
          <div>
            <div>1</div>
            <div>2</div>
            {[1, 2, 3].map((item) => {
              return (
              <p key={item}>{item}</p>
              <i>{item}</i>
              );//报错
            })}
          </div>
        );
        
        //map中返回用一个div包起来的原根节点,此时div才是根节点。
        let root = ReactDOM.createRoot(document.getElementById("root"));
        root.render(
          <div>
            <div>1</div>
            <div>2</div>
            {[1, 2, 3].map((item) => {
              return (
                <div>
                  <p key={item}>{item}</p>
                  <i>{item}</i>
                </div>
              );
            })}
          </div>
        );
        
      • 如果既不想让其只有一个根节点,也想让包外层盒子不占据层级结构,可以使用<></>–React.Fragment。

        //使用<></>
        let root = ReactDOM.createRoot(document.getElementById("root"));
        root.render(
          <div>
            <div>1</div>
            <div>2</div>
            {[1, 2, 3].map((item) => {
              return (
                <>
                  <p key={item}>{item}</p>
                  <i>{item}</i>
                </>
              );
            })}
          </div>
        );
        
        //使用<></>就相当于使用<React.Fragment></React.Fragment>
        let root = ReactDOM.createRoot(document.getElementById("root"));
        root.render(
          <div>
            <div>1</div>
            <div>2</div>
            {[1, 2, 3].map((item) => {
              return (
                <React.Fragment>
                  <p key={item}>{item}</p>
                  <i>{item}</i>
                </React.Fragment>
              );
            })}
          </div>
        );
        
        //使用<></>设置不了key,使用<React.Fragment></React.Fragment>可以设置key。
        let root = ReactDOM.createRoot(document.getElementById("root"));
        root.render(
          <div>
            <div>1</div>
            <div>2</div>
            {[1, 2, 3].map((item) => {
              return (
                <React.Fragment  key={item}>
                  <p>{item}</p>
                  <i>{item}</i>
                </React.Fragment>
              );
            })}
          </div>
        );
        
    4. 基于胡子语法渲染的内容,都被当做普通字符串进行渲染,无法识别其内部的HTML标签。

      • 类似于vue中的类似于v-text。

      • 如果需要可以把字符串中的标签自动识别,就需要用到dangerouslySetInnerHTML标签,dangerouslySetInnerHTML={{__html: html标签变量}};

        let str = `我的名字是:哈哈哈! <a href=''>呵呵呵</>`
        <div dangerouslySetInnerHTML={{
          __html: str
        }}></div>
        
    5. jsx中的事件绑定,是基于React内部的合成事件处理的,以onXxx的形式。

      <div onClick={ev=>{
          //.....
      }}></div>
      
      let root = ReactDOM.createRoot(document.getElementById("root"));
      root.render(
        <div
          onClick={() => {
            console.log("打印");
          }}
        >
          <div>1</div>
          <div>2</div>
        </div>
      );
      
  4. jsx的底层渲染机制

    1. 基于babel-preset-react-app语法包,把jsx编译为React.createElement()这种格式。
      • 凡是HTML标签或组件,都会被编译为React.createElement()这种格式。

        React.createElement(
          标签名/组件名,
          属性对象/null,  //->存储了给标签设置的各种各样的属性
          后续参数都是其子节点
        )
        
        • 未转化之前:

            <div
              onClick={() => {
                console.log("打印");
              }}
            >
              <div></div>
              <div id="aa" class="theclassname">fang子元素</div>
            </div>
          
        • 转化之后:

          /*#__PURE__*/React.createElement("div", {
            onClick: function onClick() {
              console.log("打印");
            }
          }, /*#__PURE__*/React.createElement("div", null), /*#__PURE__*/React.createElement("div", {
            id: "aa",
            "class": "theclassname"
          }, "fang\u5B50\u5143\u7D20"));
          
        • 转化清简之后:

          React.createElement(
            "div", 
            {
              onClick: function onClick() {
                console.log("打印");
              }
            }, 
            React.createElement("div", null), 
            React.createElement(
              "div", 
              {
                id: "aa",
                "class": "theclassname"
              }, 
              "fang\u5B50\u5143\u7D20"
            )
          );
          
        • babel转化jsx成虚拟DOM – 网址,需要会勾选选项

      • 虚拟DOM对象:框架自己创建的一个普通对象。

    2. 把createElement方法执行,创建出对应的VirtualDOM(虚拟DOM对象),也被称为:jsx元素对象。
      • 虚拟DOM:框架内部自己构建的一个对象,用来描述和记录元素标签的相关特征。

        VirtualDOM = {
          $$typeof: Symbol(react.element), //标识
          type: "div", //标签名或者组件
          key: "10",
          ref: "AAA",
          props: {
              除key/ref外其它设置的属性,
              children:子节点集合「可能没有、可能是一个值、可能是一个数组」
          }
        }
        
      • 真实DOM:交给浏览器渲染的、或者是渲染完毕后看到的元素标签、再或者是基于js获取到的原生DOM对象(有浏览器内置的属性和方法)。

    3. 基于render方法,把创建的VirtualDOM渲染为真实的DOM。
  5. jsx语法<template>模块语法

    • Vue2/Vue3中,既有<template>模块语法,也支持jsx语法。

    • React中只有jsx语法。

    • 对于同一个需求:

      • vue思路-<template>模块语法

        state/data = {
          flag:true,
          arr:[...],
          text:'...',
          level:2
        }
        <template>
          <div class="box">
              <button v-if="flag">{{text}}</button>
              <span v-for="item in arr" :key="item.id">
                {{item.title}}
              </span>
              <h1 v-if="level===1">我是标题</h1>
              <h2 v-else-if="level===2">我是标题</h2>
              <h3 v-else-if="level===3">我是标题</h3>
          </div>
        </template>
        
      • React思路-jsx语法

        state/data = {
          flag:true,
          arr:[...],
          text:'...',
          level:2
        }
        <div className="box">
          {flag?<button>{text}</button>:null}
          {arr.map(item=>{
              return <span key={item.id}>
                  {item.title}
              </span>
          })}
          {React.createElement(`h${level}`,null,'我是标题')}
        </div>
        
    • JSX语法比<template>模版语法具备更强的编程性(或者template是弱编程性的语法),构建视图更加的灵活方便!

React视图编译的机制

  • 总结:React视图编译的机制。
    1. 把jsx语法,基于 babel-preset-react-app得到React.createElement()的层级结构,React.createElement() 创建出相应的 VirtualDOM
    2. 如果是第一次渲染视图,直接基于 render() 方法,把 VirtualDOM 变为 真实DOM,并且把本次创建的VirtualDOM缓存起来。
    3. 当视图更新的时候,会重新的按照最新的数据,把 jsx 编译为一个全新的 VirtualDOM,并且用 新的VirtualDOM 和之前 旧的VirtualDOM 进行对比(DOM-diff),计算出差异的部分,最后只把差异的部分进行更新!

业务开发思路

  • 业务开发涉及。
    • 组件式开发 – 增加可复用性和可维护性。
      • 组件间通信。
    • 全局数据管理。
    • 单页面应用。
      • 基于路由更换组件。

进阶参考

  1. 把jsx标签语法转成虚拟DOM – babeljs
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值