1.React是什么
React是一个构建用户界面的JavaScript库,用于实现组件化开发
2.什么是组件化
将一个复杂的页面分割成若干个独立的组件,每个独立组件各自有自己的业务逻辑以及样式,这样将一个复杂的页面独立分割成独立组件的方式就是组件化
特点:
-
可组合
-
可复用
-
好维护
3.React由什么组成
React有两个核心库组成,分别为
react.js,react-dom.js,老版本只有react.js库
react.js:是React的核心库
react-dom.js:用于提供与DOM相关功能,render方法用来向浏览器插入DOM元素
4.JSX
4.1什么是JSX
JSX可以理解为使用JS和HTML混合组成的一种语法,将组建的结构,数据以及样式组合在一起定义的组件,JSX其实只是一种语法糖,最终通过babeljs转译成
createElement语法
JSX
<div className='container'>
<p style={{color:'#f00'}}></p>
<button onClick={this.btnHandler}>submit</button>
</div>
通过babeljs转译:
"use strict";
React.createElement("div", {
className: "container"
}, React.createElement("p", {
style: {
color: '#f00'
}
}), React.createElement("button", {
onClick: (void 0).btnHandler
}, "submit"));
createElement后:
{
"type":"div",
"props":{
"className":"container",
"children":[
{
"type":"p",
"props":{
"style":{
"color":"#f00"
},
"children":[
]
}
},
{
"type":"button",
"props":{
"onClick":"btnHandler()",
"children":[
"submit"
]
}
}
]
}
}
注意:
如果createElement后的结果通过JSON.stringify()后onClick丢失,这里是为了更好的看create后的结果,通过JSON.stringify()转换,然后将OnClick手动添加上去的
4.2更新元素渲染
React元素都是
immutable不可变的,当元素被创建完成之后,你是无法改变其内容和属性的。更新界面的唯一办法是创建一个新的元素,然后将它传入React.render()方法
import React from 'react';
import ReactDOM from 'react-dom';
let num=0
function counter() {
const element = (
<div>
{num++}
</div>
);
ReactDOM.render(element, document.getElementById('root'));
}
setInterval(counter, 1000);
4.3React只会更新变化的部分
ReactDOM首先会比较元素内容先后的不同,然后在渲染过程中只更新变化的部分,即使我们每秒都创建了一个描述整个UI树的新元素,ReactDOM也只会更新渲染文本节点中发生变化的内容
5.组件&Props
组件的创建方式有两种,一种是函数式组件,一种是类组件
组件类似于函数,接受任意的入参(props),并返回用于描述页面展示内容的React元素
5.1函数组件
function Wellcome(props){
return <div>hello,{props}</div>
}
5.2类组件
class Wellcome extends React.Component{
render(){
return (
<div>hello,{this.props}</div>
)
}
}
5.3Props的只读性
无论使用函数或者类声明的组件,它都不能修改自己的props
所有的React组件必须像
纯函数那样使用它们的props
纯函数:
-
如果函数的调用参数相同,则永远返回相同的结果。它不依赖于程序执行期间函数外部任何状态或数据的变化,必须只依赖于其输入参数
-
该函数不会产生任何可观察的副作用
6.状态state
组件的数据来源一个是属性对象,一个是状态对象
属性是父组件传递过来的
状态是组件自身的,改变状态的唯一方式是setState
属性和状态的变化都会影响视图的更新
6.1.setState
改变属性的唯一方式setState,不能通过this.state=xxx
class Counter extends React.Component{
state={
num:0
}
render(){
const {num}=this.state
return (
<>
<p>{num}</p>
<button onClick={()=>this.setState({num:num+1})}>增加</button>
</>
)
}
}
ReactDOM.render(<Counter/>,document.getElementById('root'))
6.2.State的更新可能是异步的
-
为了优化性能,React可能会把多个setState()调用合并为一个调用
-
如果要依赖更新完成的值,我们可以通过setState(state=>(),()=>{})方式
class Counter extends React.Component{
state={
num:0
}
add=()=>{
this.setState({num:this.state.num+1})
console.log('a',this.state.num)//0
this.setState({num:this.state.num+1})
console.log('b',this.state.num)//0
this.setState(state=>(
{num:state.num+1}
),()=>{
console.log('c',this.state.num)//3
});
this.setState(state=>(
{num:state.num+1}
),()=>{
console.log('d',this.state.num)//3
});
}
render(){
const {num}=this.state
return (
<>
<p>{num}</p>
<button onClick={this.add}>增加</button>
</>
)
}
}
ReactDOM.render(<Counter/>,document.getElementById('root'))
6.3数据是单向向下流动
React中state只会影响自己或者依赖它的子组件
7.事件处理
-
React的事件是通过驼峰命名的
-
使用JSX语法时,需要传入函数,而不是string
-
不能通过false阻止事件默认行为,event.preventDefault阻止
class Counter extends React.Component{
add=(event)=>{
event.preventDefault()
}
render(){
return (
<>
<button onClick={this.add}>增加</button>
</>
)
}
}
7.1.this
回调中的this
箭头函数
匿名函数
bind进行绑定
class HandlerThisCom extends React.Component{
constructor(props){
super(props)
}
add1(event){
event.preventDefault()
console.log('add1')
}
add2=(event)=>{
event.preventDefault()
console.log('add2')
}
render(){
return (
<>
<button onClick={this.add1.bind(this)}>button1</button>
<button onClick={this.add2}>button1</button>
<button onClick={event=>{
event.preventDefault()
console.log('add3')
}}>button1</button>
</>
)
}
}
ReactDOM.render(<HandlerThisCom/>,document.getElementById('root'))
7.4 Ref
React为了方位DOM节点,提供了Ref
Ref三种创建方式:
ref的值是一个字符串
ref的值是一个函数
ref为React.createRef()
class RefCom extends React.Component{
constructor(props){
super(props)
this.emailRef=React.createRef()
}
getNameHandler=()=>{
const name=this.refs.name.value
console.log(name)
}
getPwsHandler=()=>{
const psw=this.psw.value
console.log(psw)
}
getEmailHandler=()=>{
const email=this.emailRef.current.value
console.log(email)
}
render(){
return (
<>
<div>
<input ref='name'/>
<button onClick={this.getNameHandler}>获取名字</button>
</div>
<div>
<input ref={input=>this.psw=input}/>
<button onClick={this.getPwsHandler}>获取密码</button>
</div>
<div>
<input ref={ this.emailRef}/>
<button onClick={this.getEmailHandler}>获取密码</button>
</div>
</>
)
}
}
ReactDOM.render(<RefCom/>,document.getElementById('root'))
7.5.forwardRef转发
-
不能在函数组件上使用ref,因为没有实例
-
Ref转发是将ref自动通过组件传递给子组件的
class Form extends React.Component {
constructor(props){
super(props);
this.input = React.createRef();
}
getFocus = () => {
this.input.current.focus();
}
render() {
return (
<>
<TextInput ref={this.input}/>
<button onClick={this.getFocus}>获得焦点</button>
</>
);
}
}
const TextInput =React.forwardRef((props,ref)=>(
<input ref={ref}/>
))
ReactDOM.render(<Form/>,document.getElementById('root'))
forwardRef的实现原理
class Form extends React.Component {
constructor(props){
super(props);
this.input = React.createRef();
}
getFocus = () => {
this.input.current.focus();
}
render() {
return (
<>
<TextInput myref={this.input}/>
<button onClick={this.getFocus}>获得焦点</button>
</>
);
}
}
const TextInput =forwardRef((props,ref)=>(
<input ref={ref}/>
))
function forwardRef(funcComponent){
return function(props){
let ref = props.myref;
return funcComponent(props,ref);
}
}
ReactDOM.render(<Form/>,document.getElementById('root'))
8.生命周期
8.1.旧版生命周期
class LifeCycler extends React.Component{
constructor(props){
super(props)
console.log('constructor')
this.state={
num:0
}
}
componentWillMount(){
console.log('componentWillMount')
}
componentDidMount(){
console.log('componentDidMount')
}
shouldComponentUpdate(){
console.log('shouldComponenUpdate')
return true
}
componentWillUpdate(){
console.log('componentWillUpdate')
}
componentDidUpdate(){
console.log('componentDidUpdate')
}
render(){
console.log('render')
const {num}=this.state
return (
<>
<p>{num}</p>
<button onClick={()=>this.setState({num:this.state.num+1})}>添加</button>
</>
)
}
add=()=>{
}
}
ReactDOM.render(<LifeCycler/>,document.getElementById('root'))
第一次渲染页面时日志:
index.js:174 constructor index.js:181 componentWillMount index.js:202 render index.js:185 componentDidMount
添加是日志:
index.js:189 shouldComponenUpdate index.js:194 componentWillUpdate index.js:202 render index.js:198 componentDidUpdate
分析:
在页面初始化刷新时,首先会调用initialzation阶段,这个阶段主要是初始化state和props,接着组件将要挂载,渲染,组件挂载完成;
再点击添加时,首先调用了shouldComponentUpdate方法,此方法可以对React进行优化,接着将要更新,渲染,更新完成
shouldComponentUpdate:
状态更新时触发,如果返回值为false,后续的componentWillUpdate,render,componentDidUpdate将不会在调用,React中的PuerComponent就是通过这个方法做了一些优化
shouldComponentUpdate(nextProps,nextState){ // 代表的是下一次的属性 和 下一次的状态
return nextState.num%2;//可以对数据进行一些处理
}
componentWillReceiveProps:
第一次渲染时不会执行,之后属性更新时才会执行,有一个参数newProps
componentWillUnMount:
组件卸载是调用
8.2.新生命周期
新的生命周期
去掉了:
componentWillMount,
componentWillUpdate,
componentWillReceiveProps,
新增了:
getDerivedStateFromProps
getSnapshotBeforeUpdate
class ParetLifeCycler extends React.Component{
constructor(props){
super();
this.state = {number:0}
}
handleClick=()=>{
this.setState({number:this.state.number+1});
};
render(){
return (
<>
<p>{this.state.number}</p>
<ChildLifeCycler number={this.state.number}/>
<button onClick={this.handleClick}>+</button>
</>
)
}
}
class ChildLifeCycler extends React.Component{
constructor(props){
super(props)
console.log('constructor')
this.state={
num:0
}
}
static getDerivedStateFromProps (nextProps, prevState){
console.log('getDerivedStateFromProps')
const {number} = nextProps;
return {num:number+1}
}
componentDidMount(){
console.log('componentDidMount')
}
shouldComponentUpdate(){
console.log('shouldComponenUpdate')
return true
}
componentDidUpdate(){
console.log('componentDidUpdate')
}
getSnapshotBeforeUpdate (){
console.log('getSnapshotBeforeUpdate')
return null
}
render(){
console.log('render')
return (
<>
<p>{this.state.num}</p>
</>
)
}
}
第一次渲染时:
index.js:242 constructor index.js:249 getDerivedStateFromProps index.js:271 render index.js:254 componentDidMount
点击加号:
index.js:249 getDerivedStateFromProps index.js:257 shouldComponenUpdate index.js:271 render index.js:266 getSnapshotBeforeUpdate index.js:262 componentDidUpdate
getDerivedStateFromProps:
static getDerivedStateFromProps(props,state)是将传入的props映射到state上面
static getDerivedStateFromProps(nextProps, prevState) {
const {number} = nextProps;
// 当传入的type发生变化的时候,更新state
if (number%2==0) {
return { number:number*2};
}else{
return { number:number*3};
}
// 否则,对于state不进行任何操作
return null;
}
getSnapshotBeforeUpdate:
getSnapshotBeforeUpdate() 被调用于render之后,可以读取但无法使用DOM的时候。它使您的组件可以在可能更改之前从DOM捕获一些信息(例如滚动位置)。此生命周期返回的任何值都将作为参数传递给componentDidUpdate()