React
虚拟 DOM
React 不直接操作真实 DOM,而是通过渲染虚拟 DOM 到真实页面。因为有优秀的 DIFF 算法能够保证重用 DOM。
JSX 语法
- 定义虚拟 DOM 不写引号
- 标签中有 JS 加{}
- 样式类名不用 class 用 className
- 内联样式要
style={ {key:value} }
- 只有一个根标签
- 标签必须闭合
- 标签首字母
- 小写则转为 html 标签无论是否存在,例:div、name
- 大写则渲染为 react 对应组件,无则报错
JS 的类
1 2 3 4 5 6 7 8 9 10 11 12
| class Pet { constructor(name){ this.name = name; } }
class Cat extends Pet { constructor(name, age){ super(name); this.age = age; } }
|
super()是调用父类的构造函数,也是将父类的 this 传递给子类,否则子类是用不了 this 对象的。
类定义的方法都是放在原型对象上。这句话引出的例子就是:
1 2 3 4 5 6 7 8 9 10 11 12
| class Weather extends React.Component { constructor(pros){ super(props);//调用父类构造器,传递this对象 this.changeWeather = this.changeWeather.bing(this); //将原型对象上的changeWeather传递给Weather的实例对象并且绑定了this } changeWeather() { //放在了Weather的原型对象上 //隐藏了'use strict' console.log(this); } }
|
类中的 this
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Person { constructor(name) { this.name = name; } study() { //类中的方法有隐形的'use strict' console.log(this); } } const p1 = new Person('tom') p1.study() //this指向Person const x = p1.study // x() //等于函数直接调用study(),又因为严格模式所以输出的是undefined
|
类的简写
首先的知识点就是在 class 里可以随便写赋值语句,但不可以随便写代码
1 2 3 4 5 6 7 8 9 10 11 12
| class Weather extends React.Component { //初始化state state = { isHot:false, wind:'微风' } changeWeather = ()=> { //changeWeather赋值了一个箭头函数 //箭头函数的this会直接在外层找,在这里就是Weather console.log(this)//Weather } }
|
展开语法
用于展开数组,在官方的情况下不能展开对象,但是可以用{…object}叫做构造字面量对象时使用。
1 2 3 4 5 6 7 8 9 10 11 12
| //基本用法-合并 const arr1 = [1,2,3,4] const arr2 = [3,4,5] const arr3 = [...arr1, ...arr2] // [1,2,3,4,5]
//对象的使用场景 const obj1 = {foo:'bar', x:23} const obj2 = {foo:'bar', x:32} const obj3 = {...obj1, ...obj2}
//在React中可以展开对象是因为处于babel和react的编译中 ReactDOM.render(<Person {...p}/>, doucument.getElementById('test3'))//仅在这里可用
|
Props
组件接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。props 是只读的。
首先说一个 PropTypes 规定 prop 的类型
1 2 3 4 5 6 7 8 9
| static propTypes = { name:PropTypes.string.isRequired, age:PropTypes.number, speak:PropTypes.func } static defaultProps = { sex:'男', age:18 }
|
Ref
下面是几个适合使用 refs 的情况:
- 管理焦点,文本选择或媒体播放。
- 触发强制动画。
- 集成第三方 DOM 库。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| //string类型的方式会有“性能不好”的问题 <input ref = "input1"></input>
//最常用 //回调函数的方式在更新过程中会被调用两次,一次null,一次真实DOM对象,但大部分情况无关紧要 <input ref ={ c => this.input1 = c}></input> //定义成绑定class的绑定函数解决上述问题 saveInput = (c) => this.input1 = c; <input ref ={this.saveInput}></input>
//最推荐 //React.createRef 调用后生成一个容器,用于储存ref标识的节点 input1 = React.createRef() ......//省略代码 <input ref={this.input1}></input> //使用的时候是 console.log(this.input1.current.value)
|
Fragment
用来躲避 JSX 必须要指定一个根标签的情况
1 2 3 4 5
| import {Fragment} from 'react' ... <Fragment key={}> ... </Fragment>
|
Context
用来在祖组件和后代组件中传递状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const XxxContext = React.createContext()
<XxxContext.Provider value ={数据,可是对象} 子组件 </XxxContext.Provider>
//方式一:仅适用于类组件 static contextType = XxxContext this.context//可以读取了 //方式二:引入Consumer <XxxContext.Consumer> { value => {value就是返回的数据} }
|
PureComponent
Component 中,只要执行 setState(),即使不改变状态,依旧调用 render(),父组件的 render()会触发子组件的 render()。
原因:Component 中的 shouldComponentUpdate()总返回 true。
而 PureComponent 解决了上述问题。
但:
- 只进行 props 和 state 的浅比较,如果只是对象内部数据改变,那不会触发 render()
- 子组件也要是 PureComponent。
RenderProps
类似 Vue 的 slot,可以在父组件中传一个子组件。
1 2 3 4
| <Parent render={(name)=><Son name={name}} />
//父组件中jsx加上 {this.props.render(this.state.name)}
|
ErrorBoundary
只能用在生产环境,开发环境使用会照样报错.
getDerivedStateFromError 和 componentDidCatch 一般配合使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| state = { hasError: false }; static getDerivedStateFromError(error) { return { hasError: true }; }
componentDidCatch(error, info) { //统计页面的错误,发送请求到后台 console.log(error, info); }
render() { return ( <div>{hasError ? <h2>当前网络不稳定,稍后再试</h2> : <Child />}</div> ); }
|
Hooks
useState
1 2 3 4
| // useState返回一个数组,接收一个参数设置为初始值 // 数组第一个为变量名,接受参数为初始值 // 第二个为设置变量的函数 const [count, setCount] = useState(0)
|