这是我参与「第五届青训营 」笔记创作活动的第6天。
本堂课重点内容
本堂课学习了React的设计思路以及基本使用。
详细知识点介绍
设计思路
一言以概之,React的主要设计思路包括:
-
响应式编程
- 对于事件来说,我们执行既定的回调,之后状态进行变更,然后UI进行更新
-
组件化
- 组件是组件的组合/原子组件
- 组件内拥有状态,外部不可见
- 父组件可将状态传递到子组件内部
-
状态归属
- 当前状态归属于两节点向上寻找到的最近的祖宗节点
类组件
以一个基本的tab栏为例
基本代码结构(父):
import React, { Component } from 'react'
export class App extends Component{
constructor() {
super()
this.state = {
titles: ["流行", "新款", "精选"],
tabIndex: 0
}
}
tabClick(tabIndex){
this.setState({tabIndex})
}
render(){
const {titles,tabIndex} = this.state
return(
<div className='app'>
<TabControl titles={titles} tabClick={i => this.tabClick(i)} />
<h1>{titles[tabIndex]}</h1>
</div>
)
}
}
基本代码结构(子):
import React, { Component } from 'react'
import "./style.css"
export class TabControl extends Component {
constructor() {
super()
this.state = {
currentIndex: 0
}
}
itemClick(index) {
this.setState({ currentIndex: index })
this.props.tabClick(index)
}
render() {
const { titles } = this.props
const { currentIndex } = this.state
return (
<div className='tab-control'>
{
titles.map((item, index) => {
return (
<div
className={`item ${index === currentIndex?'active':''}`}
key={item}
onClick={e => this.itemClick(index)}
>
<span className='text'>{item}</span>
</div>
)
})
}
</div>
)
}
}
export default TabControl
对于render函数来说,当没有state和props变化时,我们不需要再次运行render函数,所以我们可以使用pureComponent(类组件)或memo(函数式组件)来进行性能优化。
当我们使用class来创建React组件时,还有一个很麻烦的事情:this的指向。为了保证this的指向正确,我们通常要采用箭头函数,或者使用this.handleClick = this.handleClick.bind(this)这种代码,增加了心智负担。
函数式组件
对于无状态的函数式组件来说,我们可以通过使用Hooks来保存状态,同时大大简化代码。
import { useState } from 'react';
function Example(props) {
const [count, setCount] = useState(0);
const {name} = props;
return (
<div>
<p>{name} clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
对于hooks来说,react规定我们必须把hooks写在函数的最外层,不能写在ifelse等条件语句中,来确保hooks的执行顺序一致。
而对于类组件中的生命周期钩子,我们可以使用useEffect来进行替代,对每一个副作用函数使用一个单独的useEffect钩子,这样一来使代码的逻辑也变得更加清晰。
useEffect:
- 第一个参数传递副作用函数
- 副作用函数return的函数来清除副作用影响
- 第二个参数规定副作用的范围数组