react基础
1.1 特点
声明式编码(原来是命令式编码)
高效,采用虚拟DOM+优秀的Diffing算法来实现DOM的的渲染,最大限度的减少DOM操作。
灵活,跟其他库灵活搭配使用
JSX,俗称JS里面些HTML,javascript语法的扩展
组件化,模块化。代码容易复用。
单向数据流。没有实现数据的双向绑定
React Native中可以使用React语法进行移动端开发
1.2 React与js对比
原生js操作DOM会造成浏览器大量的重绘重排 原生js没有组件化编码方案,代码复用率低 原生DOM渲染的时候不管之前有没有相同,都会去大量重绘和重排 但是虚拟DOM会先比较一下原来的虚拟DOM,把新修改或添加的内容渲染上去就行了,减少了重绘和重排的次数
1.3 真实DOM与虚拟DOM
虚拟DOM本质是一个Object类型的对象(一般对象) 虚拟DOM的属性比较少,真实DOM的属性比较多。因为虚拟DOM只是React内部在用,无需真实DOM上那么多的属性 虚拟DOM最终会被转化为真实DOM。呈现在页面上。
2 创建项目
2.1 通过script引入使用,仅用于学习调式使用
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
2.2 创建hello React
注意:引入顺序,且在定义虚拟DOM的时候不用加引号
2.3 通过react脚手架创建项目
npm install -g create-React-app create-react-app 项目名称
3jsx的使用
3.1 jsx的使用规则:
定义虚拟DOM时,不要写引号 标签中混入JS表达式时要用{} 样式的类名指定不要用class,要用className 内联样式,要用style={{key:value}}的形式去写 只有一个根标签 标签必须闭合 标签首字母若小写,就会去根html中标签进行匹配找不到就报错, 标签首字母若大些,react就会去渲染对应的组件,若组件没有定义,则报错
3.2 jsx的小练习
补充:什么是表达式 表达式会产生一个值,能用变量接收的都是表达式 需求:列表动态渲染
注意:不能在jsx里面写js语句,只能写js表达式 补充:什么是表达式? 表达式会产生一个 值,能用变量接收的都是表达式 不要忘了加{ }因为在标签中混入JS表达式时要用{ }
4组件
4.1 函数式组件(简单组件)
render的时候注意组件名字首字母要大写,标签后面要闭合 React解析步骤:React先解析组件标签,找到了Mycomponent组件,发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,渲染在页面上
4.2 类式组件(复杂组件)
在定义类式组件的时候要继承于React的内置类Component 记得要类式组件的要写render(){ } 要有return返回值,返回值式组件中的内容 也不要忘了组件的开头要大写 render是放在Myconponents的原型对象上,供实例使用。 在render中的this指向的是Mycomponents实例对象(组件实例对象) React解析步骤: React解析组件标签,找到Myconponents组件。 发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。 将render返回的虚拟DOM转为真实DOM,随后呈现在页面上
4.3(类)组件实例的三大核心属性 state
4.3.1 初始化state:
在初始化state的时候需要使用constructor和super 参数是props, constructor中可以定义this.state的内容 在render的return返回值中可以使用state中的属性 4.3.2 react中的事件绑定
先定义事件,再在组件中调用事件 onclick变成了onClick on后面的第一个字母要大写 demo函数后面不需要加()如果加了的话,会自动调用一次 4.3.3 类中的this指向问题
在construstor和render中的this指向的是组件实例 但是changeWeather属于直接调用,在类中会自动开启严格模式,而且在babel也开启了严格模式。所以这里的this为undefined 解决类中的this指向问题
如上图changeWeather放在了组件实例的原型上,所以等号左边可以通过原型链找到changeWeather方法,通过bind把这个指向变成了当前的this(也就是这个组件实例对象) 在右边通过接收这个函数,然后就可以使用啦。因为此时的changeWeather中的this指向的组件实例对象了。而不是undefined
4.3.4 setState的使用
使用setState改变state中的属性,而不能直接改变 这里改变属性是一中合并而不是替换,除了setState中重新改变的属性以外,其他的不变(保留) 这里有点击事件 constructor调用了一次,因为就只用了一次组件 这里有点击事件 render调用了n+1次 1次是初始化的时候 n是点击的次数(重新渲染的次数) 这里有点击事件 changeWerther调用了n次 点几次就调用几次 4.3.5 简化state写法
在类中直接写a=1这样的语句,即使没有声明a,也会自动变成a的属性。 同理state 和 changeWeather也可以这样。 changeWeather用赋值的形式定义,并且用箭头函数。这样可以自动函数内的this指向该组件实例 4.3.4 state总结 state是组件对象最重要的属性,值是对象(可以包含多个key-value值的组合) 组件被称为“状态机”,通过更新组件的state来更新对应的页面显示(重新渲染组件) 组件中render方法中的this为组件实例对象 组件自定义的方法this为undefined如何解决 a. 强制绑定this 通过函数对象的bind() b. 箭头函数 状态数据,不能直接修改或更新,需要使用setState()
4.4(类)组件实例的三大核心属性 props
4.4.1props基本使用
在调用组件的时候,可以传过去一些属性 组件实例内部有一个props会自动接收传过来的属性 可以利用this . props . 属性名来拿到传过来的属性 也可以先结构赋值,再使用这些属性 4.4.2 展开运算符补充
基本使用:展开运算符可以展开数组直接运算,但是不能直接展开对象类型 配合reduce实现对任意长度的数组进行求和 如果要展开对象类型,需要使用{...Person} 的方式。也是内置语法糖。而且此时的Person2与Person类似于深拷贝,改变其中某一属性互不影响 合并 : 在展开对象类型的时候,也可以修改属性和添加属性,(其余的保留) 4.4.3批量传递props
注意:这里的{ . . .p}并不是对象类型的展开运算符。而是react解析的。{ }内部相当于表达式,里面只是 . . .p 而已。所以要根据react定义的规则,只能在标签上这样使用 4.4.4 props限制
在定义完类式组件后,可以定义该组件的props传递规则 Person . propTypes 是Person中的专门用来存放限制的规则 开头的p小写 name: 中的PropType是导入的一个包, 开头的P是大写 ,是一个全局的变量用来具体该属性的限制,string表示限制类型,isRequired表示必须要传 defaultProps 是Person中的专门用来存放默认值的 同时也可以传递函数类型的属性,但是要注意类型用func 而不是function 4.4.4 props简写
可以把propTypes和defaultProps写在定义(类式)组件的内部 4.4.5 在函数式组件中使用props
在组件标签中写上要传递的值,用props参数接收,然后结构,就可以正常使用啦 也可以规定数据类型的限制和默认值。但是只能写在函数的外面啦 4.4.5 总结props 每个组件对象都会有props属性 组件标签的所有属性都保存在props中 通过标签属性从组件外向组件内传递变化的数据 组件内部不能修改props属性(只读属性) 内部读取某个属性值: this . props . name 导入prop-types库来为传过来的属性类型做限制 扩展属性:将对象的所有属性通过props传递 <Person { ... p} /> Person.defaultProps设置默认属性值
4.5(类)组件实例的三大核心属性 refs
4.5.1字符串形式使用ref(过时)
在标签上添加ref属性,这样在组件内部就可以使用refs.ref属性名来访问这个标签 注意:在标签上添加的是ref 在使用的时候是refs 由于是字符串形式,所以ref的属性值是字符串类型 4.5.2回调函数形式使用ref
c => this.input = c 在这里是这个箭头函数,c为参数,该参数实际上就是该元素节点 在showData中结构赋值,因为当前实例有input1属性,所以可以接收到input1 使用input1这个元素节点中的一些属性 在标签中 只有ref这样的函数会自动调用,并且会把当前元素节点传进去 调用次数的问题:如果改变了页面(重新触发render)这个内联形式的ref回调函数会触发两次 4.5.3 createRef使用ref
在类式组件中定义myRef1并接收React的内置方法createRef(),表示创建了一个用来存放ref的容器(一个ref对应一个容器) 在标签中的ref上使用this.myRef1 在自定义事件showData中使用ref,不要忘记固定的current(myRef1是键值对的形式,current是键,元素节点是值) 4.5.4 ref总结 尽量避免字符串形式的ref(执行效率低,但是写起来方便)
4.6 react的事件处理
特点: 通过onXxxx属性指定事件处理函数(注意大小写) React使用的是自定义(合成)事件,而不是使用的原生DOM事件 —— 为了更好的兼容性 React中的事件是通过事件委托处理的(委托给组件最外层的元素)——为了高效 通过event . target 得到发生事件的DOM元素对象 ——不要过度使用ref 4.7非受控组件与受控组件 非受控组件(现取现用) 受控组件:类似于vue中的双向绑定,输入类型的标签每一次更新都会更新在state中,并实时更新
5 组件的生命周期(旧)
常用的钩子: componentDidMount(组件渲染完成)一般在这个钩子中做初始化的事 例如:开启定时器,发送网络请求, 订阅消息 2. componentWillUnmount(组件将要卸载) 一般在这个钩子中做一些收尾的事 例如:关闭定时器, 取消订阅 3. render
钩子流程: 正常创建卸载 父组件渲染向子组件传的数据有更新(初次不算 ) 组件数据更新 强行刷新 注意: 在父组件传值的时候,第一次不会触发componentWillReceiveProps 第二次才会触发 shouldComponentUpdata这个钩子不调用的话有默认返回值为true,表示允许更新 但是如果要用这个钩子,就必须要写返回值,ture表示允许更新,false表示不允许更新
6 组件的生命周期(新)
替换了三个will变成了getDerivedStateFromProps 必须有返回值,是对象类型,表示的是强行变成这个状态
getSnapshotBeforeUpdate 获取快照,在更新之前,保留一些信息在return中返回,以便于在之后使用
补充: componentDidUpdate(组件更新完成) 有三个默认参数,一般使用preProps(之前的Props) preState(之前的State) snapshotValue(快照值)
、
diff即different(不同)用来比较新的虚拟DOM和旧虚拟DOM有何不同
经典面试题:
key有什么作用?
简单的说,key是虚拟DOM对象的标识,在更新显示时key起着极其重要的作用
详细的说:当状态中的数据发生变化的时候,react会根据新数据生成新的虚拟DOM
随后react进行新虚拟DOM与旧虚拟DOM的diff比较,比较规则如下:
旧虚拟DOM中找到了与新虚拟ODM相同的key:
若虚拟DOM中的内容没变,直接使用之前的真实DOM
若虚拟DOM中内容变了,则生成新的真实DOM,随后替换页面中之前的真实DOM
旧虚拟DOM中未找到与新虚拟DOM相同的key
根据数据创建新的真实DOM,随后渲染到页面
为什么遍历的时候key最好不用index
若对数据进行:逆序添加、逆序删除等破坏顺序操作;
会产生没有必要的真实DOM更新 ==> 界面效果没问题,但效率低
2.如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==> 界面有问题
3.注意:如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,
仅用于渲染列表用于展示,使用index作为key也可以
在开发中如何选择key
最好使用每条数据的唯一标识作为key,比如:id号 手机号 身份证好 学号等唯一值(后端提供的)
如果确定只是简单的展示数据,用index也是可以的