大家好👋,我是一个工作了一年的PPT工具人和项目催命丸,坐标上海,现在打算辞职转岗前端开发😝。
从4月底开始,在B站跟着尚硅谷的男神天禹老师学习React,目前学到了第58节,发现很多知识都没有好好去理解,内化。所以,暂时停止看视频学习,回头来总结复习一下。 写博客是一个很好的督促自己坚持学习、坚持复盘的方法,今天我就在这里立一个flag!在未来3个月内,每周更新一篇前端学习的帖子!如果我没有按时更新,欢迎大家来评论区砸场子,随便批评!
Ps: 强烈推荐B站天禹老师的【尚硅谷React技术全家桶完整版】教程。保姆式教学,讲课细致,幽默风趣。听着上头,学到痴迷~ 特别适合小白~
前言
React是用于构建用户界面的JavaScript库,起源于Facebook的内部项目。 React框架做的本质工作就是吃入数据,吐出UI,把声明式的代码转换为命令式的 DOM 操作,把数据层面的描述映射到用户可见的 UI 变化中去。
一、React相关js库
前期先写html代码引入库,后续用脚手架后即开始使用import进行导入
<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- 引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!-- 引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<!-- 引入prop-types,用于对组件标签属性进行限制 -->
<script type="text/javascript" src="../js/prop-types.js"></script>
二、组件实例的三大属性
1. state
常用于通过状态中的数据驱动页面的更新/显示。 state的初始值支持各种数据类型,包括null,string或者object对象,只要是javascript允许的都可以。
<body>
<div id="test"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
//1.创建组件
class Weather extends React.Component{
//初始化状态
state = {isHot:false,wind:'微风'}
//render调用几次? ———— 1+n次, 初始化1次,状态更新n次数
render(){
const {isHot,wind} = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
}
//用类创建组件时,组件中所有的自定义方法 ———— 都要用赋值语句的形式+箭头函数
//箭头函数没有自己的this,若在箭头函数中使用了this关键字,不会报错,会寻找外层函数的this作为箭头函数的this
//changeWeather调用几次? ———— 点几次,调几次
changeWeather = ()=>{
const isHot = this.state.isHot
//要借助一个内置的API(setState)去更改状态,且更新是一种合并,不是替换
this.setState({isHot:!isHot})
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))
</script>
</body>
2. props
props是一个从外部传进组件的参数,主要用于从父组件向子组件传递数据,它具有可读性和不变性。
(1)每个组件对象都会有props(properties的简写)属性
当需要向一个组件传递数据的时候,我们使用props,比如<FunctionalComponent name="Shiori" />
,name就是Component的一个props属性。
(2)组件标签的所有属性都保存在props中
(3)内部读取某个属性值:this.props.propertyName
(4)作用:通过标签属性从组件外 向组件内传递数据(只读 read only)
(5)用propTypes对props中的属性值进行类型限制和必要性限制
//对标签属性进行类型、必要性的限制
Person.propTypes = {
name:PropTypes.string.isRequired, //限制name必传,且为字符串
sex:PropTypes.string, //限制sex为字符串
age:PropTypes.number, //限制age为数值
speak:PropTypes.func, //限制speak为函数
}
3. refs
简介: 访问 DOM 节点 / 访问在render方法中创建的React元素;组件内的标签可以定义ref属性来标识自己;调用React.createRef后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的。
注:元素是构成 React 应用的最小单位,它用于描述屏幕上输出的内容。组件由元素构成。
1)字符串形式的ref
<input ref="input1" type="text" placeholder="点击按钮提示数据"/>
2)函数形式的ref
<input ref={(currentNode)=>{this.input1 = currentNode}} type="text" placeholder="点击按钮提示数据"/>
三、React两大组件
1. 函数式组件
也称无状态组件(可使用React Hooks:useState改变state),一般用于静态没有交互事件内容的组件页面,没有this困扰且代码简洁,便于逻辑的拆分复用。函数组件是面向过程编程思维方式。
sequenceDiagram
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
Alice-)John: See you later!
<body>
<div id="test"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
// 1.创建函数式组件
function MyComponent(){
console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式
return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
}
// 2.渲染组件到页面 (将组件MyComponent渲染到id为test的标签中)
ReactDOM.render(<MyComponent/>,document.getElementById('test'))
/*
1) React解析组件标签,找到了MyComponent组件
2) 发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
*/
</script>
</body>
2. 类式组件
类式组件又称为动态组件,一般用于有交互事件或数据修改的组件页面。类组件是面向对象编程思维方式。
<body>
<div id="test"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
// 1.创建类式组件
class MyComponet extends React.Component {
console.log('render中的this:',this); //this指向的是当前组件的实例对象
return <h2>我是用类定义的组件(适用于【复杂组件】的定义</h2>
}
}
// 2.渲染组件到页面
ReactDOM.render(<MyComponent/>,document.getElementById('test'))
/*
1) React解析组件标签,找到了MyComponent组件;
2) 发现组件是使用类定义的,随后【new出该类的实例】,并【通过该实例调用】到原型上的render方法;
3) 将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
*/
</script>
</body>
3. 函数组件和类式组件对比总结:
区别 | 函数组件 | 类组件 |
---|---|---|
生命周期 | 无 | 有 |
this | 无 | 有 |
state | 无 | 有 |
改变state | React Hooks:useState | this.setState() |
性能 | 高(不用实例化) | 低(需要实例化) |
四、事件处理
- 通过onXxx属性指定事件处理函数(注意大小写,小驼峰,如onClick)
1) React使用的是自定义(合成)事件, 而不是使用的原生DOM事件(更好的兼容性)
2) React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)(高效)
- 通过event.target得到发生事件的DOM元素对象(当发生事件的元素和操作的元素是同一个时,可以借助事件对象event.target拿到值,尽量避免使用ref,注意不要过度使用ref)
五、收集表单数据
1. 非受控组件
页面中所有输入类DOM,现用现取,即为非受控组件。例如:input框的输入值是当点击登录按钮时才被获取到。
<Input defaultValue={x} ref={input}/>
2. 受控组件
页面中所有输入类DOM,随时输、随时就把值维护到状态中,需要用的时候直接从状态中取出来,即为非受控组件。
<Input value={x} onChange={fn}/>
3. 对比
区别 | 非受控组件 | 受控组件 |
---|---|---|
一次性取值(例如:提交时) | √ | √ |
提交时验证 | √ | √ |
即时现场验证 | × | √ |
有条件地禁用提交按钮 | × | √ |
强制输入格式 | × | √ |
一个数据的多个输入 | × | √ |
动态输入 | × | √ |
六、高阶函数_函数柯里化
高阶函数:如果有一个函数符合下面2个规范中的任何一个,就为高阶函数。
1.若A函数,接收的参数是一个函数,那么A即为高阶函数
2.若A函数,调用的返回值依然是一个函数,那么A即为高阶函数
常见的高阶函数有:Promise、setTimeout、arr.map()等等
函数柯里化:通过函数调用,继续返回函数的方式,实现多次按接收参数,最后统一处理的函数编码形式。
七、组件的生命周期
生命周期回调函数 <=> 生命周期钩子函数 <=> 生命周期钩子 <=> 生命周期函数
ComponentWillMount() 组件将要挂载的钩子
componentDidMount() 组件挂载完毕的钩子,组件挂载页面完毕后调用,只调用一次
shouldComponentUpdate() 控制组件更新的“阀门”
componentWillUpdate() 组件将要更新的钩子
render()
componentDidUpdate() 组件更新完毕的钩子
componentWillReceiveProps(props) 组件将要接收新的props的钩子
static getDerivedStateFromProps(props,state) 从Props得到一个派生的状态。如果state的值在任何时候都取决于props,可以使用该方法。派生状态会导致代码冗余,并使组件难以维护。
getSnapshotBeforeUpdate() 在更新之前获取快照
最核心最常用的三个钩子:render()、componentDidMount()、componentWillUpdate()
旧生命周期图:
新生命周期图:
八、DOM的Diffing算法
1. Diffing算法
React首先生成虚拟DOM,再转换为页面的真实DOM。DOM更新时, react 会先与之前的虚拟DOM做对比,和之前一样的节点可复用,不会重新渲染;与之前不同的节点,则重新生成。
2. key的作用
经典面试题:
Q1. react/vue中的key有什么作用?(key的内部原理是什么)
虚拟DOM中key的作用:
1)简言之:key是虚拟DOM对象的标识,在更新显示时key起着极其重要的作用。
2)详细说:当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】,
随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:
a.旧虚拟DOM中找到了与新虚拟DOM相同的key:
①若新虚拟DOM中内容没变,直接使用之前的真实DOM
②若内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
b.旧虚拟DOM中没有找到与新虚拟DOM相同的key:
根据数据创建新的真实DOM,随后渲染到页面
Q2. 为什么遍历列表时,key最好不用index?
用index作为key可能会引发的问题:
1) 若对数据进行:逆序添加、逆序删除等破环顺序操作:
会产生没有必要的真实DOM更新 ==> 界面效果没问题,但效率低。
2)如果结构中还包含输入类DOM:
会产生错误DOM更新 ==> 界面有问题
3)注意!如果不存在对数据的逆序添加、逆序删除等破环顺序操作,
仅用于渲染列表用于展示,使用index作为key是没有问题的。
Q3. 开发中如何选择key?:
1)最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。
2)如果确定只是简单的展示数据,用index也是可以的。
———————————————————————————
暂时就写到这里8,本小白渣第一次写技术博客,写完了我都不想发布了😭,不管这么多,先完成、再完善😳。如果有不对的地方,欢迎各位在评论区指出,谢谢!(^^ゞ
🚩flag来了:本周会继续挤时间学习组件化编程,把todolist的案例做完后,即学完第64课后,下一篇博客将会在5月15日更新。