React中级学习(第二天)

JSX 语法的转化过程 (了解)

演示 : babel中文网试一试 let h1 =

  • JSX 仅仅是createElement() 方法的语法糖 (简化语法)
  • JSX 语法 被 @babel/preset-react 插件编译为 createElement() 方法
  • React 元素:是一个对象,用来描述你希望在屏幕上看到的内容
  • React 元素 最后 被 ReactDOM.render(<Child/>,document.getElementById('root')) 渲染显示到页面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9hqEG5rw-1596329786917)(C:/Users/wangyu123/Desktop/新建文件夹/面试题/md-imgs/jsx.png)]

  • 演示:
render () {const el = <h1 className='greeting'>Hello JSX</h1>console.log(el);return el
}react更新机制 
简化 : 虚拟DOM
然后呢?? 
1. jsx => 虚拟DOM  => 真实的DOM
2. jsx数据发生变化 => 新的虚拟DOM
3. 新的虚拟DOM 和 旧的虚拟DOM对比 => 通过Diff算法找到有差异的地方 => 更新1步骤的真实的DOM

组件更新机制

  • setState 的两个作用
    • 修改state
    • 重新调用render , 更新组件(UI)
  • 过程 : 父组件重新渲染时, 也会重新染当前组件子树

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l4SpZboe-1596329786920)(C:/Users/wangyu123/Desktop/新建文件夹/面试题/md-imgs/更新机制.png)]

演示代码 :

  • App > P1+P2> C1+C2
//2. 类组件
class App extends React.Component {state = {}render() {return (<div style={{ background:'pink', display:'flex' }}><P1></P1><P2></P2></div>)}
}
class P1 extends React.Component {render() {return (<div style={{ background:'red',flex:1 }}><p>P1</p></div>)}
}
class P2 extends React.Component {state = {name :'zs'}render() {return (<div style={{ background: 'skyblue',flex:1 }}><p onClick={this.handle}>P2- { this.state.name }</p><C1></C1><C2></C2></div>)}handle = () => { this.setState({name : 'ls'})}
}
class C1 extends React.Component {render () {console.log('child1 更新了');return (<div style={{background:'yellow' }}><p>child1</p></div>)}
}
class C2 extends React.Component {render () {console.log('child2 更新了');return (<div style={{background:'lime' }}><p>child2</p></div>)}
}
  • 这样效果是出来了,但是它确实有很严重的性能问题, 因为子组件都没有任何变化,如果重新渲染,那么就会重新调用render() 渲染页面, 有损性能
  • 所以需要进行处理 组件性能优化

组件性能优化

优化1: 减轻 state

  • 原则 : state 中 只存储跟组件渲染相关的数据 (比如 : count / 列表数据 等)
  • 不用做渲染的数据 不要放在 state 中, (比如 定时器 id )
// 定时器的 timerId 就 不需要放到state 中,, 只是用来清除 定时器, 和渲染无关componentDidMount() {// timerId存储到this中,而不是state中this.timerId = setInterval(() => {}, 2000)}componentWillUnmount() {clearInterval(this.timerId) }

优化2 : 避免不必要的重新渲染

  • 组件更新机制 : 父组件更新会引起子组件也被更新
  • 问题 : 子组件没有任何变化时, 也会重新渲染
  • 如何避免不必要的重新渲染呢 ?
  • 解决方式 : 使用 钩子函数` shouldComponentUpdate(nextProps, nextState)
    • nextProps : 最新的属性
    • nextState : 最新的状态
    • 场景 : 比较更新前后的 state 或者 props 是否相同, 来决定是否 更新组件
  • 作用 : 通过返回值 决定该组件是否需要重新渲染, 返回true ,表示重新渲染, false 表示不重新渲染
  • 触发时机 : 更新阶段的钩子函数, 组件重新渲染 执行
    • 顺序 : shouldComponentUpdate() ==> render() ==> componentDidMount()
  • 演示 : 点击父组件的计算器的数据count
// 演示1 : 子组件里 通过 shouldComponentUpdate()  { return true or false } - true-更新- false-不更新// 演示2 : 获取 父传过来的属性, 奇数更新,偶数不更新,  shouldComponentUpdate(nextProps,nextState)- nextProps : 最新的属性- nextState : 最新的状态- if(nextState.count % 2 == 0) {return false    }else { return true}// 演示3 : 就一个组件里有number 值, 点击产生随机值, 比较前后生成的随机值是否一致,不一致就更细, 一致就不需要更新
// count : Math.floor(Math.random()*3)shouldComponentUpdate(nextProps,nextState) {//          上一个的值                  最新的值console.log(this.state.count === nextState.count)// 本次的 nextState.number// 上一次的 this.state.number//  或者 通过 if..else..判断 return this.state.count !== nextState.count}

优化3 : 纯组件 - PureComponent

  • 纯组件
  • 作用 : 自动实现了 shouldComponentUpdate() 钩子函数, 不需要再手动对比更新前后的props 或者 state , 来阻止不必要的更新了
  • 原理 : PureComponent 内部, 会别对比更新前后的props 以及更新前后的state , 只要有一个不同, 就会让组件更新, 只有在两者都相同的情况下, 才会阻止组件更新
class Hello extends React.PureComponent {}
// 把那个方法 shouldComponentUpdate() 删除掉, 已经 PureComponent已经封装好了

PureComponent 内部原理

参考 : API Reference => React => React.PureComponent

  • PureComponent

  • 说明 : PureComponent 内部会比较更新前后的 props 和 state 分别进行浅对比

  • 对于简单/值类型来说, 比较两个值是否相同 (直接赋值即可, 没有坑)

// 将 React.Component 替换为: React.PureComponent
class Hello extends React.PureComponent {state = {// number 就是一个普通的值类型的数据number: 0}handleClick = () => {const newNumber = Math.floor(Math.random() * 3)console.log(newNum);// 对于 值类型 来说,没有任何坑,直接使用即可// 更新前的 number:0// 更新后的 number:2// PureComponent 内部会进行如下对比:// 更新前的number === 更新后的number//    如果这两个值相同,内部,相当于在 shouldComponentUpdate 钩子函数中返回 false ,阻止组件更新。//    如果这两个值不同,内部,相当于在 shouldComponentUpdate 钩子函数中返回 true ,更新组件。this.setState({number: newNumber})}render() {return (<div><h1>随机数:{this.state.number}</h1><button onClick={this.handleClick}>随机生成</button></div>)}
}
  • 对于引用类型来说, 只比较对象的引用(地址) 是否相同
    • 造成的结果 : 对象里 的数据变化,不更新
const { obj } = this.statelet newNum = Math.floor(Math.random() * 3)
console.log(newNum);// 虽然value 值 也可以从 react-dev-tools 里调试 value值确实都变了,但是 obj 一直没有变
obj.value = newNumthis.setState({obj 
})
  • 正确做法 : 根据现有状态生成一个新对象, 然后再更新状态
const newObj = {...this.state.obj} // 创建一个新对象
newObj.value = Math.floor(Math.random() * 3)
this.setState({obj: newObj
})
  • 正确做法说明:
    • 在 PureComponent 中 使用引用类型 的状态时, 应该每次都创建一个新的状态, 而不是直接修改当前状态
    • 因为PureComponent 是浅对比, 所以,如果直接修改当前对象中的属性, 会造成: 对象中的值变了, 但是引用地址没有改变, 而导致组件不会被更新, 这样的话就出现bug了
  • 注意 , 在 React 中, ( 不管是PureComponent 还是 Component ) , 都不要直接修改引用类型的状态值, 而是要创建一个新的状态, 修改新的状态,然后再更新

在 React 组件 中更新应用类型的状态

  • 文档 : 不可变数据的力量
  • 注意 : 对于引用类型的状态来说, 应该创建新的状态, 而不要直接修改当前状态
  • 原则 : 状态不可变!!! 数据不要变, 直接创建新的
  • 对象状态 :
// 对象
state = {obj : {value : 123}
}//ES5
//                            新加     之前的值      修改内容
const newObj = Object.assign( {}, this.state.obj, {value : '新的值'} )
this.setState({obj:newObj
})
// es6 
this.setState({obj : {...this.state.obj, value: '新的值'}
})
  • 数组状态
// 数组:
state = {list: ['a', 'b']
}// ES5:
this.setState({list: this.state.list.concat([ 'c' ]) // ['a', 'b', 'c']
})// ES6:
this.setState({list: [...this.state.list, 'c']
})// 删除数组元素:[].filter()

虚拟DOM的真正价值

  • 虚拟 DOM 的真正价值从来都不是性能。
  • 真正的价值:虚拟DOM 能够让 React 摆脱浏览器的限制(束缚)。也就是,只要能够运行JS代码的地方,就能够运行 React。
  • 跨平台
    • JSX => 虚拟DOM => react-dom => DOM 元素=> 浏览器
    • JSX => 虚拟DOM => React-Native => ios和安卓的元素 => 移动混合开发
    • JSX => 虚拟DOM => 工具 => VR

React 组件

  • (state, props) => UI

路由基础

路由介绍

  • 路由 : 就是一套映射规则, 是url中 哈希值展示视图 之间的一种对应关系
  • 为什么要学习路由 ?
    • 现代的前端应用大多都是 SPA(单页应用程序),也就是只有一个 HTML 页面的应用程序。
    • 因为它的用户体验更好、对服务器的压力更小,所以更受欢迎。
    • 为了有效的使用单个页面来管理原来多页面的功能,前端路由 应运而生。
  • 使用React路由简单来说,就是配置 路径组件(配对)
spa缺点1. 学习成本大 学习路由2. 不利于SEO

基本使用

  • 安装 : yarn add react-router-dom
// 1 导入路由中的三个组件
import { BrowerRouter , Link, Route } from 'react-router-dom'const Hello = () => {// 2 使用 BrowerRouter 组件包裹整个应用(才能使用路由)return (<BrowerRouter><div><h1>React路由的基本使用:</h1>{/* 3 使用 Link 组件,创建一个导航菜单(路由入口) */}<Link to="/first">页面一</Link>{/* 4 使用 Route 组件,配置路由规则以及要展示的组件(路由出口) */}<Route path="/first" component={First} /></div></BrowerRouter>)
}

常用组件的使用介绍

  • 引入的三个组件
// HashRouter => 哈希模式 => 带 #  => 修改的是 location.hash
import { HashRouter , Link, Route } from 'react-router-dom'  //带#
// BrowserRouter => history模式 => 不带 #  => 修改的是 location.pathname
import { BrowserRouter , Link, Route } from 'react-router-dom'  //不带#
  • BrowserRouter 组件 : 使用 Router 组件包裹整个应用 (才能使用路由)
  • Link 组件 : 创建一个导航菜单 (路由入口)
    • 最终会生成一个a标签, 通过 to 属性指定 pathname(history /) 或 hash(哈希模式 #)
  • Route 组件 : 用来配置路由规则和要展示的组件 (路由出口)
    • path : 配置路由规则
    • component : 指定当前路由 规则匹配时要展示的组件
    • Route 组件放在哪, 组件内容就展示在哪, 并且每一个路由都是一个单独的Route组件

路由的执行过程

  • 当点击 Link 的时候,就会修改浏览器中的 pathname
  • 只要 浏览器地址栏中的 pathname 发生改变,React 路由就会监听到这个改变
  • React 路由监听到 pathname 改变后,就会遍历所有 Route 组件,分别使用 Route 组件中的 path 路由规则,与当前的 浏览器地址栏中的pathname进行匹配
  • 只要匹配成功,就会把当前 Route 对应的组件,展示在页面中
  • 注意:匹配时,不是找到第一个匹配的路由就停下来了。而是: 所有的 Route 都会进行匹配,只要匹配就会展示该组件。
    • 也就是说:在一个页面中,可以有多个 Route 同时被匹配

使用 Switch 组件 ,匹配一个

{/* Switch 只会让 组件显示出来一个 */}
<Switch><Route path="/one" component={One}></Route><Route path="/two" component={Three}></Route><Route path="/two" component={Two}></Route>
</Switch>

编程式导航

  • 改变入口的三种方式 :

  • 手动输入

  • 声明式导航 : (html)

    • 编程式导航 : 通过js代码来实现的跳转/返回 (js)
  • 编程式导航 :

  • 可以通过props 拿到 跳转和返回的方法

  • 正常的组件, 打印 props => 默认是 一个空对象 {}

  • 凡是参与路由匹配出来的组件 , 路由都会给他们传入三个属性 history, location, match

  • history : (主要用来编程式导航)

    • push() 跳转到另外一个页面 push(path,state)
    • goBack() 返回上一个页面
    • replace() 跳转到另外一个页面
  • location : (位置路径的)

  • pathname : 路径

    • state : 通过跳转传递的数据
  • match : 获取参数

    • params : 可以拿到动态路由里的参数 params : {id : 123}
 * - push()  跳转到另外一个页面* - goBack() 返回上一个页面* - replace() 跳转到另外一个页面** - push 和 replace 区别* - 	push()    跳转 - 记录访问的历史  (可逆)* - 	replace() 跳转 - 不记录访问的历史 (不可逆)* One :  <button onClick={this.jump}>跳转到two</button> 演示* Two :  <button onClick={this.back}>返回到One</button> 返回

HashRouter 传参的方式和 BrowserRouter 传参的方式不一样this.props.history.push({pathname: '/pay',state: {name: 'zs'}})

默认路由 - 根路径 /

  • 默认路由地址为:/
  • 默认路由在进入页面的时候,就会自动匹配
{/* / 表示默认路由规则 */}
<Route path="/" component={Home} />

匹配模式

问题:当 Link组件的 to 属性值为 “/login”时,为什么 默认路由/ 也被匹配成功?

  • 默认情况下,React 路由是: 模糊匹配模式
  • 模糊匹配:只要 pathname 以 path 开头就会匹配成功
    • path 代表Route组件的path属性
    • pathname 代表Link组件的to属性(也就是url中 location.pathname)
  • 精确匹配:只有当 path 和 pathname 完全匹配时才会展示该路由
  • 解决办法 : 给 Route 组件添加 exact 属性,让其变为精确匹配模式
// 添加  exact 之后, 此时,该组件只能匹配 pathname=“/” 这一种情况
<Route exact path="/" component=... />// 再演示 : /one/two/three 

重定向

  • 需求 : 使用 重定向 '/' => '/one'
  • 方式1 : render-props
<Route exact path='/'render={ () => {return <Redirect to='/one' />}
}></Route>
  • 方式2 - children
<Route exact path='/'><Redirect to='/one' />
</Route>

路由两种模式的说明

哈希模式

 1. 访问路径 :  http://localhost:8080/#/one http://localhost:8080/#/two2. 服务器接收到的 (服务器是不会 接收 # 后面的内容的)3. 不管访问的路径是什么样的 http://localhost:8080  ==> 服务器返回的默认 的就是  index.html4. 后面的 /one 和 /two 由路由来使用, 根据路由匹配规则找到对应的组件显示
5. 哈希模式 不管是 开发阶段还是发布阶段,都是没有问题的

history 模式

1. 访问路径 :  http://localhost:8080/one http://localhost:8080/two2. 服务器接收到的 http://localhost:8080/one  和 http://localhost:8080/two但是,/one 和 /two 这个路径是不需要服务器端做任何处理的。
3.  http://localhost:8080/getNewshttp://localhost:8080/detail 它们都是 接口地址  , 后面遇到 类似 /one 和 /two 都会以为是接口 是要返回数据的呢?
3. 所以,应该在服务器端添加一个路由配置,直接返回 SPA 的 index.html 页面就行啦。
4. 类似处理app.get('/getNews', (req,res) => {// 根据 res 返回 对应的数据res.json { .....  }})app.get('/detail', (req,res) => {// 根据 res 返回 对应的数据res.json { .....  }})// 最后 额外再多加一个, 专门用来返回 index.htmlapp.use('*', (req,res) => {res.sendFile('index.html')})

总结 :

history模式 : 
- 开发阶段 :  webpack脚手架已经处理好了, 
- 发布阶段 : 服务器是公司的服务器, 可能就会报错
- 我们要做的就是`告诉后台`,我们使用的 是 history模式,让他专门处理一下,就可以了
- 如果后台不给处理,或者处理不好, 我们就使用 `哈希模式`

类似 /one 和 /two 都会以为是接口 是要返回数据的呢?
3. 所以,应该在服务器端添加一个路由配置,直接返回 SPA 的 index.html 页面就行啦。
4. 类似处理
app.get(’/getNews’, (req,res) => {
// 根据 res 返回 对应的数据
res.json { … }
})
app.get(’/detail’, (req,res) => {
// 根据 res 返回 对应的数据
res.json { … }
})

// 最后 额外再多加一个, 专门用来返回 index.html
app.use('*', (req,res) => {res.sendFile('index.html')
})

#### 总结 : ```js
history模式 : 
- 开发阶段 :  webpack脚手架已经处理好了, 
- 发布阶段 : 服务器是公司的服务器, 可能就会报错
- 我们要做的就是`告诉后台`,我们使用的 是 history模式,让他专门处理一下,就可以了
- 如果后台不给处理,或者处理不好, 我们就使用 `哈希模式`

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/247909.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【】MTCNN基于NCNN的测试过程

前言 操作过程 NCNN: https://github.com/Tencent/ncnn/wiki/how-to-build#build-for-linux-x86; vector初始化&#xff1a;int num[4] { 1, 4, 3, 2 }; int numLength sizeof(num) / sizeof(num[0]); vector<int> nums(num, num numLength); //使用数组初始化向量 Q&…

iOS NSTextAttachment - 图文混排

苹果在iOS7中推出了一个新的类NSTextAttachment&#xff0c;它是做图文混排的利器&#xff0c;本文就是用这个类&#xff0c;只用50行代码实现文字与表情混排&#xff0c;当然也可以实现段落中的图文混排。 首先说一下文字和表情的混排&#xff1a; 先来做点儿准备工作&#…

vuex的结构有哪些参数?

查看参考地址&#xff1a; https://vuex.vuejs.org/zh/ vuex 状态管理模式&#xff0c;相当于数据的中间商 注意&#xff1a; 为相同 属性有&#xff1a; 1.State vue中的data —> 存放数据 2.Getter vue中的计算属性computed —>将已有的数据进行计算再次利用 3.…

百炼OJ - 1004 - 财务管理

题目链接&#xff1a;http://bailian.openjudge.cn/practice/1004/ 思路 求和取平均。。。 #include <stdio.h>int main() {float sum0,a;for(int i0;i<12;i){scanf("%f",&a);sum a;}printf("$%.2f\n",sum/12);return 0; } 转载于:https://w…

iOS 自定义Cell按钮的点击代理事件

在实际开发工作中&#xff0c;我们经常会在自定义的Cell中布局一些按钮&#xff0c;并且很多时候我们会在点击这个按钮的时候使我们的UItableviewController跳转到下一界面&#xff0c;有的可能还要传值。那么如何使我们的控制器能够获知我们按下了cell的按钮呢&#xff1f;毫无…

Google 开源技术protobuf 简介与样例

今天来介绍一下“Protocol Buffers ”&#xff08;以下简称protobuf&#xff09;这个玩意儿。本来俺在构思“生产者/消费者模式 ”系列的下一个帖子&#xff1a;关于生产者和消费者之间的数据传输格式。由于里面扯到了protobuf&#xff0c;想想干脆单独开一个帖子算了。 ★prot…

VUE全局导航守卫、 请求、响应拦截器 的设置

文件设置参考地址&#xff1a;https://gitee.com/wang_yu5201314/headlines__news/tree/master/%E9%A1%B9%E7%9B%AE%E6%BA%90%E7%A0%81%E6%96%87%E4%BB%B6/src 文件夹 Router 文件夹 index.js 中设置 全局导航守卫 文件 mian.js 中设置 请求、响应拦截器 设置 请求、响应拦截器…

JRE System Library和 Referenced Libraries 的区别和来源

JRE System Library 安装jdk后&#xff0c;会有个目录叫做jrejre目录是核心类库&#xff0c;目录中装的是类库文件jre System Library顾名思义就表示系统类库文件 Referenced Libraries referenced libraries放的是你引用的jar包&#xff0c;这个不需要自己创建的&#xff0c;你…

ByteArray、16进制、字符串之间的转换

ByteArray、16进制、字符串之间的转换&#xff1a; package fengzi.convert {import flash.utils.ByteArray;public class ByteArrayTranslated{/**** 通过hax数据返回ByteArray* param hax 格式 "AA5A000100FF"***/public static functi…

js - (初中级)常见笔试面试题

1.用 js 实现一个深拷贝 2.用 js 写一个数组去重 3. 用 js 对字符串进行反转 4. 用 js 请求范围内的质数个数 5.用 js 求数组中出现最多的数及其出现次数

iOS 支付宝SDK接入详解

一&#xff0c;在支付宝开放平台下载支付宝SDK&#xff08;https://openhome.alipay.com/platform/document.htm#down&#xff09; https://doc.open.alipay.com/doc2/detail.htm?spma219a.7629140.0.0.HpDuWo&treeId54&articleId104509&docType1 二&#xff0c;添…

面试基本知识点

文章目录面-什么是SEO面 - cookie / localstorage / sessionstorage的区别面 - promise面试题面 - 柯里化函数面 - 函数节流面 - 函数防抖HTML / CSS 知识点1、讲讲盒模型&#xff08;蚂蚁金服 2019.03 招行信用卡 2019.04 美团 作业帮&#xff09;2、根据盒模型解释边距重叠&a…

Redis 热点key

压测报redis 热点问题 热点问题概述 产生原因 热点问题产生的原因大致有以下两种&#xff1a; 用户消费的数据远大于生产的数据&#xff08;热卖商品、热点新闻、热点评论、明星直播&#xff09;。 在日常工作生活中一些突发的的事件&#xff0c;例如&#xff1a;双十一期间某些…

移动IM开发那些事:技术选型和常见问题

最近在做一个iOS IM SDK&#xff0c;在内部试用的阶段&#xff0c;不断有兄弟部门或者合作伙伴过来问各种技术细节&#xff0c;所以统一写一篇文章记录&#xff0c;统一介绍下一个IM APP的方方面面&#xff0c;包括技术选型(包括通讯方式,网络连接方式,协议选择)和常见问题。 …

webstrom打开通过顶部浏览器打开网页,被跳转到默认主页

重新开始工作啦&#xff0c;希望以后认真一点&#xff0c;并把遇到的问题都记录下来&#xff0c;虽然是小小白&#xff0c;但能无意间帮助到别人就更开心了呀 通过webstrom打开本地的文件时&#xff0c;发现跳转到了默认主页上&#xff0c;吐槽下&#xff0c;有些主页真的超级流…

mockjs(接口服务代理)

mock官网&#xff1a;http://mockjs.com/ 一、搭建一个练习项目 1.利用vue的项目脚手架进行搭建 命令&#xff1a; vue create mock-demo 截图&#xff1a; 2.安装相关的依赖 命令&#xff1a; #使用 axios 发送 ajax npm install axios --save #使用 mock.js 产生随机数据…

MD5算法原理

MD5&#xff08;单向散列算法&#xff09; 的全称是Message-Digest Algorithm 5&#xff08;信息-摘要算法&#xff09;&#xff0c;经MD2、MD3和MD4发展而来。MD5算法的使用不需要支付任何版权费用。MD5功能&#xff1a;输入任意长度的信息&#xff0c;经过处理&#xff0c;输…

函数-函数进阶-装饰器流程分析

老王&#xff1a;算了&#xff0c;估计你也想不出来。。。学过嵌套函数没有&#xff1f; 你&#xff1a;yes&#xff0c;然后呢&#xff1f; 老王&#xff1a;想实现一开始你写的america login(america)不触发你函数的执行&#xff0c;只需要在这个login里面再定义一层函数&am…

制作手写签名

<!DOCTYPE html> <!-- saved from url(0056)http://hao2013.cn/canvas-special-master/brush/index.html --> <html><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"><title>签名板(支持移动…

python第五次作业——陈灵院

习题1&#xff1a;读入文件pmi_days.csv&#xff0c;完成以下操作&#xff1a;1.统计质量等级对应的天数&#xff0c;例如&#xff1a;优&#xff1a;5天良&#xff1a;3天中度污染&#xff1a;2天2.找出PMI2.5的最大值和最小值&#xff0c;分别指出是哪一天。 import csv impo…