React根据项目总结

        就如同看书一样,一千个人眼里,有一千个哈姆雷特,每个人的理解都有不同,想要找到作者最为准确的意思,还是要到官网站查询

官网:React 官方中文文档 – 用于构建用户界面的 JavaScript 库

 

目录

净美仕PC端官网项目全流程开发架构​编辑​编辑

一、React概述

二、JSX

三、React中的数据绑定

  ①内容绑定

  ②属性绑定

  ③样式绑定

  ④事件绑定

  ⑤双向数据绑定

  ⑥条件渲染 —— React中没有“指令”的概念

  ⑦列表渲染

四、React中自定义组件

五、经典面试题:React中this指向丢失问题 及 解决方案

五一、组件的状态数据(State)

六、React中的父子组件见传参

七、class组件的生命周期方法

八、重点/难点:Hook

九、不同架构的路由导航模块:

十、React基于浏览器项目的路由导航模块:react-router-dom

十一、React中异步请求服务器端接口

十二、ReactNative组件库


净美仕PC端官网项目全流程开发架构

 

 

一、React概述

  英文官网:https://reactjs.org/

  中文网站:https://zh-hans.reactjs.org/

  用于构建用户界面的 JavaScript 库 —— React只涉及到JS,不涉及HTML/CSS;

特点1:声明式(数据响应式) —— MVVM框架典型特征

特点2:组件化

特点3:一次学习,到处使用 —— 适用于网站、H5、WebApp、原生App

  由Facebook/Meta在2013年5月开源,目前最新稳定版是v18.2。

  项目中使用React的两种方式:

方式1:脚本引入式 —— 在页面中用<script src="react.js | react-dom.js | babel.js">

方式2:脚手架方式 —— 在开发端使用Node.js/Webpack/开发服务器环境运行/打包React应用

  ①安装正确版本的Node.js

       node  -v      必须大于等于V14.0

  ②下载全局脚手架工具,并运行它,创建一个新的项目(项目名称不能包含汉字/大写字母)

       npx   create-react-app   项目名   

  ④进入项目目录,启动其中自带的开发服务器         

       cd  项目名

       npm  start

JSX

  JSXJavaScript XML使用XML语法创建JS对象的技术。这种语法本身是TypeScript的一部分。

  JSX在React中不是必需的;

  如果使用了,同时还需要引入babel.js编译器;

  所有的JSX都将被编译为:React.createElement( )

  语法要求如下:

   ①JSX语法是严格的“XML语法”:标签必须结束、属性值必须有引号、标签名/属性名区分大小写;

②一段JSX中可以添加任意换行;

③一段JSX中有且只能有一个父元素;如果不想引入无用的父元素,可以使用:

<></>  或  <React.Fragment></React.Fragment>

④JSX中的注释写作:  {/*  注释内容  */}

⑤JSX中元素的属性不等同于HTML标签的属性,例如:class写作className、value写作defaultValue、onclick写作onClick、onmouseover写作onMouseOver....

⑥JSX中事件处理函数中的this不指向“事件源对象”(不是真实DOM元素)、也不指向window,而指向undefined(事件处理函数是运行在“严格模式”下的全局函数——Babel编译后的结果都是运行在“严格模式”)

⑦JSX要求:HTML标签对应的组件名必须用纯小写形式;自定义组件名必须用“大驼峰命名法”

⑧JSX中的所有的style都不能赋值为字符串——及时原生DOM中style也不是字符串!而是对象!

React中的数据绑定

  ①内容绑定

<span>{表达式}</span>

  ②属性绑定

<img src={表达式}/>

  ③样式绑定

<div style={表达对象}  className={表达式}></div>

  ④事件绑定

<button onClick={表达式}></button>

形式1:处理函数不需要传参    onClick={f1}

形式2:处理函数需要传参    onClick={()=>f2(实参)}

  ⑤双向数据绑定

Vue.js中使用v-model指令实现双向数据绑定;React中没有指令的概念,只能模拟实现:

Model=>View: <input value={uname}/>

View=>Model: <input onChange={e=>setUname( e.target.value )}/>

  ⑥条件渲染 —— React中没有“指令”的概念

类似于Vue.js中的v-show指令——修改display样式:

<div style={display: this.state.show?'block':'none'}>

类似于Vue.js中的v-if指令——{}中只能出现表达式,if不是:

{ this.state.show && JSX } if...

{ this.state.show ? JSX1 : JSX2 } if...else...

  ⑦列表渲染

React中没有指令的概念,没有v-for或类似的语法!

{ arr.map( (item,index)=>(JSX) ) }

技术

innerText绑定

innerHTML绑定

原生JS

e.innerText = '内容'

e.innerHTML = '内容'

Vue.js

<div>{ {内容}}</div>

<div v-text="内容"></div>

<div v-html="内容"></div>

小程序/uni-app

<text>{ {内容}}</text>

<rich-text nodes="内容"/>

React

<div>{内容}</div>

<div dangerouslySetInnerHTML={ {__html: "内容"}}></div>

React中的“单一数据源”和“受控组件”的概念:

在React中,一个输入框或类似的表单字段,只允许存在一个数据源:要么是键盘输入,要么是模型变量;即:

  没有指定value属性,那么用户可以使用键盘随意输入——数据源就是键盘输入;

  如果指定value属性,那么只有value属性绑定的模型变量改变了输入框内容才能改变,键盘无法输入了——数据源就是模型变量;此时,输入框被模型变量“控制”,称为“受控组件”。

“受控组件”和“非受控组件”—— 面试题

受控组件:程序需要监控用户的每一次输入,确保每次输入都是合法的 —— onChange

非受控组件程序无需监控用户的每次输入,只需最后提交的时候可以读取到最终的内容即可

//受控组件 —— 适用于需要监控每次输入

let [kw, setKw] = useState("")

let doKwChange = (e)=>{

    setKw(e.target.value)

}

<input value={kw} onChange={doKwChange}/>

//非受控组件 —— 无需监控用户的每次输入

let kwInput = useRef( )

doSubmit(){

   let v = kwInput.current.value

}

<input  ref={kwInput}  defaultValue="默认值"/>

面向过程(Procedure)的编程思想把任务分为多个步骤,每个步骤用一个函数来实现

面向对象(Object)的编程思想把任务涉及到的数据/方法划分为不同的角色,角色之间互相发消息

四、React中自定义组件

 React中提供了两种创建自定义组件的语法:

 语法1:函数式组件(体现的是面向过程的编程思想——类似于C语言)

function XzRating( props ){ //创建子组件

return JSX

}

let vchild = <XzRating/> //使用子组件

 语法2:式组件(体现的是面向对象的编程思想——类似于Java语言)

class XzRating extends React.Component{ //创建子组件

render(){  return JSX   }

}

let vchild = <XzRating/> //使用子组件

五、经典面试题:React中this指向丢失问题 及 解决方案

this指向undefined问题出现在:

① class组件中  ②是事件处理函数中

问题分析

1)this不会指向事件源对象 —— JSX=>React.createElement()=>创建的都是虚拟DOM对象

2)this也不指向window —— JSX=>"use strict",严格模式下函数中的this不指向window

3)严格模式下,全局函数中的this永远指向undefined

解决方案:

方案1:箭头函数(无法传参)

f1 = ()=>{ log(this) }

onClick = {this.f1}

方案2:箭头函数(可以传参)

f1(形参){ log(this) }

onClick = {()=>this.f1(实参)}

方案3:使用bind(函数多次使用就要多次bind,从而生成多个副本)     

f1(){ log(this) }

onClick = {this.f1.bind(this)}

方案4:使用bind

constructor(){

  super()

  this.f1 = this.f1.bind( this )

}

f1(){ log(this) }

onClick = {this.f1}

五一、组件的状态数据(State)

 Vue.js中,组件的状态数据是“Push-Based”——数据的改变会自动推送出去,告诉渲染系统重新渲染;

 微信小程序中,组件的状态数据是“Pull-Based”——程序必须明确的告诉渲染系统组件数据被改变了,请重新渲染;
 React中,组件数据采用“Pull-Based”,即组件的状态数据改变必须明确的通知渲染系统。

 声明组件的状态数据

state = { //类似于Vue.js中的data

uname: "yaya",

upwd: "123456",

products: [...],

}

 修改组件的状态数据:

this.state.uname = 'yadan' //不会在页面中重新渲染

this.setState({ uname: 'yadan' })   //修改状态变量的同时通知渲染系统

 提示:

  ①setState方法如果仅修改了state中的部分数据,其它数据会自动合并进来(不会丢失)

  ②setState方法因为既要修改状态数据,又要通知渲染系统修改真实DOM树,比较耗时间,此方法对数据的修改是“异步的”

  ③如果想查看异步修改后的状态数据,只能使用setState方法的第二个参数:“异步修改后的回调函数”

this.setState( state,  ()=>{ 此函数在数据修改后+组件重新渲染后执行 } )

六、React中的父子组件见传参

  父组件 => 子组件 —— “Props Down

//Parent

state = {age:18}

<Child childAge={this.state.age}/>

//Child

<div>{this.props.childAge}</div>

//Parent

let [age] = useState(18)

<Child childAge={age}/>

//Child

<div>{props.childAge}</div>

  子组件 => 父组件 —— “Props Up”(不是Events Up

//Parent

let doNum = function( num ){  log(num)  }  //父组件有个方法需要num,但是自己却没有该数据

<Child f1={doNum}/>               //child.f1 = parent.doNum

//Child

let  n  =  3   //要显示的页号

props.f1( n )    //子组件调用父组件传递来的方法,并将自己的数据作为实参

七、class组件的生命周期方法

  阶段1:挂载阶段

① constructor( ):组件对象被创建了

② render( ):渲染组件内容

③ componentDidMount( ):组件完成挂载,类似于mounted/onLoad    did-do的完成时

  阶段2:更新阶段(props或state改变)

④ shouldComponentUpdate( newProps, newState ): 此次更新应该重新渲染到视图吗?默认返回true

② render( ):渲染组件内容

  ⑥ componentDidUpdate( ):组件完成更新,类似于updated

  阶段3:卸载阶段

  ⑦ componentWillUnmount( ):组件即将卸载,类似于beforeMount

八、重点/难点:Hook

  自从React诞生,“函数式组件”功能一直有缺失:没有状态、没有生命周期方法 —— 没有父类,导致函数式组件只能编写一些简单的固定内容的组件。

  V16.8开始,官方为“函数式组件”弥补了不足——增加了“Hook”的概念,同时由于自身的优势(天然没有this),导致越来越多的程序员开始偏向使用“函数式组件”。

  当前的项目中,可以同时使用“类式组件”和“函数式组件”。

  Hook:钩子,是官方为“函数式组件”增加的新特性,用于为函数式组件“钩住”一些扩展功能。

  Hook有如下特点

  ①只用于“函数式组件”;不用与“类式组件”;

  ②所有的钩子本质都是一个函数;

  ③官方要求,钩子函数都必须以“use”卡头,形如:useXxxx( );

  ④官方要求,钩子函数只能在函数式组件内部最顶层调用,不能在内层调用;

  提示:React官方目前提供了15钩子函数,第三方模块也会提供的更多的钩子

function Rating(props){

  useXxx( )                    //正确语法

  if(){ useXxx( ) }               //错误写法

  for(){ useXxx( ) }             //错误写法

  function f1(){ useXxx( ) }     //错误写法

}

示例1:为函数式组件增加“状态变量”—— useState

import  {useState}  from  'react'

let  [ 变量名,  修改状态变量的异步方法 ] = useState(状态变量的初始值)

注意:使用useState()创建的修改方法都是异步执行的;但是与setState(state, 回调函数)不同,此处没有第二个回调函数参数!

示例2:为函数式组件增加“生命周期方法/辅助功能/副作用(SideEffect)”—— useEffect —— 难点

注意:Hook创建的生命周期方法最特别之处是:都是匿名函数,且有6个!!!

//生命周期方法1:任意数据发生改变(从无到有 + 从1到2)

useEffect( ()=>{

   //此方法 = 组件挂载 + 任意数据发生改变

} )    //没有依赖列表

//生命周期方法2:指定数据发生改变(从无到有 + 从1到2)

useEffect( ()=>{

   //此方法 = 组件挂载 + 指定数据发生改变

} , [指定数据名, ...] )   //指定了依赖列表且其中有数据

//生命周期方法3:组件挂载(数据从无到有)

useEffect( ()=>{

   //此方法 = 组件挂载 

} , [ ] )    //指定了依赖列表但其中没有数据

//生命周期方法4:任意数据发生改变直到消亡(从1到2 + 从有到无)

useEffect( ()=>{

   return ()=>{

       //此方法 = 任意数据发生改变 + 组件即将卸载

   }

} )    //没有依赖列表

//生命周期方法5:指定数据发生改变直到消亡(从1到2 + 从有到无)

useEffect( ()=>{

   return ()=>{

       //此方法 = 任意数据发生改变 + 组件即将卸载

   }

} , [指定数据名, ...])    //指定了依赖列表且其中有数据

//生命周期方法6:组件卸载(从有到无)

useEffect( ()=>{

   return ()=>{

       //此方法 = 组件即将卸载

   }

} , [ ])    //指定了依赖列表但其中没有数据

、不同架构的路由导航模块:

Vue.js:  

   vue-router

小程序/uni-app:   

   pages.json    

React(V18.2) 

   基于浏览器的项目:react-router-dom(V6.4)

   脱离浏览器的项目:react-navigation

router:路由器,类似于马路边的“百事通老大爷”

routes很多路由,路由列表,路由词典

route路由,路径经由,经由一条路径可以到达期望的目的地   路径地址 <=> 目标对象

、React基于浏览器项目的路由导航模块:react-router-dom

  英文官网:https://reactrouter.com

  没有中文官网!国内的翻译网站目前都是过时的!!

  使用步骤:

  ①安装必需的模块文件

npm  i   react-router-dom

  ②创建一个路由器对象(Router),其中包含一个路由词典(Routes),其中包含多条路由(Route)

const router = createBrowserRouter( [

{ path: '地址',  element: <组件/> },

......

] )

const root = ReactDOM.createRoot(....)

root.render(<RouterProvider router={router}/>)

  ③使用浏览器测试每个路由地址

  ④如何进行页面跳转:

模板法:<Link to="">跳转</Link>

脚本法:import {useNavigate} from 'react-router-dom'

   let  nav = useNavigate( )     //使用“导航”钩子

   nav('/地址')   //执行跳转

  ⑤如何获取当前页面所在地址

let {pathname, seach} = useLocation( )

  ⑥如何进行跳转传参

页面1:<Link to="/页面2?k1=v1&k2=v2...">跳转到页面2</Link>

页面2:let [params] = useSearchParams( )

   let v2 = params.get( 'k2' )

小知识:根据HTTP协议的规定,URL地址后面的“?k=v&k=v”称为:

  QueryString:查询字符串   或者   SearchParams:搜索参数

实现AJAX效果可用的技术:

  ①原生XHR   ②jQuery.ajax()   ③axios()    ④wx.request()/uni.request()   ⑤原生fetch

十一、React中异步请求服务器端接口

  基于浏览器的React项目,可以使用①③⑤三种方案之一进行服务器端接口异步访问。

  Fetch API:抓取/获取,是W3C委员会提供的H5新标准技术,用于取代XHR;目前除了老IE浏览器其它浏览器都原生支持。

  使用手册:https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch

//使用fetch发起GET请求

let url = ""

let res = await  fetch( url )

let data = await  res.json( )

//data就是响应消息主体解析后的JS数据

//使用fetch发起POST请求

let url = ""

let options = {

  method: 'POST',

  headers:{'Content-Type': '....'},

  body: 'k1=v1&k2=v2'

}

let res = await  fetch( url, options )

let data = await  res.json( )

//data就是响应消息主体解析后的JS数据

常见框架

常用的组件库

Vue.js

ElementUI、MintUI、VantUI...

小程序

WeUI、Vant、Taro...

uni-app

uni-ui扩展组件库

React

AntDesign、TDesign、Vant、ReactNative...

十二ReactNative组件库

  ReactNative是一个基于React框架的UI组件库,只用于移动端NativeApp,性能远超WebApp;RN组件库是业界最最特别的一个UI组件库!!!

  运行原理:RN代码(纯JS) => Webpack编译 => 得到JAVA/OC代码 => JAVA/OC编译 => .apk/.ipa => 安装到手机并运行

  

RN的魅力:让程序员不写JAVA或OC就能编写出NativeApp!!!

  官网:http://reactnative.dev/ 最新版:0.70

  中文网:https://www.reactnative.cn/

 在本机搭建RN项目开发运行环境 —— 3GB+(可能会下载失败)

 ①安装必需的编译软件:

Node.js:Webpack需要的

JDK:Java编译需要的

 ②安装Android原生App开发软件

 ③使用Android开发软件下载编译必需的第三方模块

 ④下载并安装RN项目脚手架工具,创建空白项目

 ⑤编译空白项目,得到AndroidApp安装文件

 ⑥把App安装文件安装到真实Android手机或夜神模拟器

提示:上述过程安装的软件有些只能放到 c:/users/xxx ,要求当前登录用户必须是纯英语用户名,而且权限必须管理员权限 —— 如果不是,百度搜“Windows10启用administrator账户

猜你喜欢

转载自blog.csdn.net/weixin_73416102/article/details/128032066