你要尽全力保护你的梦想。那些嘲笑你梦想的人,因为他们必定会失败,他们想把你变成和他们一样的人。我坚信,只要我心中有梦想,我就会与众不同,你也是。 —— 《当幸福来敲门》


React基础知识总结(经典好文)_数组

基础

​React​​​ 一些入门知识。用来让读者对 ​​React​​ 有一定的认识


生命周期(React Version >= 16.4)

React基础知识总结(经典好文)_数组_02

​​


生命周期钩子列表


  • ​constructor()​
  • ​render()​
  • ​componentDidMount()​
  • ​componentDidUpdate()​
  • ​componentWillUnmount()​
  • ​getSnapshotBeforeUpdate()​
  • ​shouldComponentUpdate()​


​React​​​的生命周期一共有三个阶段,分别为 ​​挂载阶段​​​、​​更新阶段​​​ 和 ​​卸载阶段​


挂载阶段


  1. ​constructor()​
  2. ​render()​
  3. ​componentDidMount()​

constructor()

  • 用于初始化内部状态
  • 唯一可以直接修改state的地方

componentDidMount()

  • 只执行一次
  • UI渲染完成后调用(类似于 ​​Vue​​​ 的 ​​mounted​​ )

render()

  • 渲染视图
  • 必须存在的


更新阶段


  1. ​shouldComponentUpdate()​​​ —— 强制更新 ( 使用 ​​this.forceUpdate()​​ ) 会跳过这个钩子
  2. ​render()​
  3. ​componentDidUpdate()​

shouldComponentUpdate()

  • 决定虚拟DOM是否要重绘,当返回值为 ​​true​​ 时会选择重绘
  • 一般可以由PureComponent自动实现
  • 常用于性能优化

componentDidUpdate()

  • 每次UI更新时被调用
  • 典型场景:页面需要根据 ​​props​​ 变化重新获取数据


卸载阶段

  • ​componentWillUnmount()​
componentWillUnmount()

  • 组件移除时调用 ( 类似于 ​​Vue​​​ 的 ​​beforeDestroy​​ )
  • 常用于释放资源 ( 例如清除定时器 )


state状态相关方法

​state​​​ 是 ​​React​​​里面存储状态的对象,相当于 ​​Vue​​​ 的 ​​data​


  • ​setState()​
  • ​forceUpdate()​

setState()

setState(updater, [callback])

​setState​​ 可接受两个参数,第二个是可选的。

使用 ​​setState​​​ 设置 ​​state​​ 有两种方式


  1. ​setState​​​ 传入对象或者函数对象,直接修改 ​​state​​ 中的数据
  2. ​setState​​​ 中传入两个函数。第一个函数有两个参数,第一个参数是当前的 ​​state​​​,第二个参数是当前的 ​​props​​​,返回的是要修改的​​state​​对象,类似于第一种设置方式;第二个函数是更新后的回调函数。

注意事项

官方建议用 ​​componentDidUpdate()​​​ 代替更新后的回调函数,其中一个原因是 ​​React​​​ 为了考虑最佳性能,会在所有 ​​setState​​ 全部执行完之后进行统一的渲染。

如果你同时使用了两次 ​​setState​​​ 修改同一个 ​​state​​ 值,会存在一些隐患。看下面这个例子

class App extends React.Component {
constructor(props) {
super(props);
this.state = { value: 0 };
}

componentDidUpdate(prevProps, prevState) {
console.log('componentDidUpdate: ' + this.state.value);
}

onClick = () => {
this.setState(
{ value: 4 },
() => console.log('onClick: ' + this.state.value));
this.setState(
{ value: 8 },
() => console.log('onClick: ' + this.state.value));
}

render() {
return <button onClick={this.onClick}>{this.state.value}</button>;
}
}

这样的代码将会打印两次 ​​onClick: 8​​​。因为这两个 ​​setState​​ 是同时处理的。


forceUpdate()

component.forceUpdate(callback) // 强制渲染组件


默认情况下,当组件的 ​​state​​​ 或 ​​props​​​ 发生变化时,组件将重新渲染。如果 ​​render()​​​ 方法依赖于其他数据,则可以调用 ​​forceUpdate()​​ 强制让组件重新渲染。



虚拟DOM和key属性

​React​​​ 使用 虚拟​​DOM​​ 的方式优化性能。

当​​React​​​组件的状态发生变化时,​​React​​​不会直接更新视图,而是创建一个新的虚拟​​DOM​​缓存所有发生变化的状态,然后等到合适的时候 一次性 更新到浏览器。

当​​React​​​组件重新渲染时,​​React​​​不会渲染整个视图,而是使用 ​​Diff​​​ 算法 比较新旧虚拟​​DOM​​ 之间的差异,然后只把 真正发生变化的地方 更新到浏览器。

虚拟DOM的两个假设


  • 组件的​​DOM​​结构是相对稳定的
  • 类型相同的兄弟节点可以被唯一标识

​key​​​属性是用来帮助 ​​React​​​ 识别那些元素改变了,从而更好的使用虚拟​​DOM​​提高性能,所以它最好是唯一的。


无状态组件和类组件

无状态组件又叫 纯函数组件 ,是没有 ​​state​​ 的组件,通常用来定义可复用的模板。

以下是一个例子。

const Component = (props) = (
<div>{props.xxx}</div>
);

类组件又称有状态组件,它是有 ​​state​​的,通常用来定义交互逻辑和业务数据。

以下是一个例子

class Home extends React.Component {
constructor(props) {
super(props);
};
render() {
return (
<Header/>
)
}
}

HOC(高阶组件)


高阶组件(HOC)是 ​​React​​ 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 ​​React API​​ 的一部分,它是一种基于 ​​React​​ 的组合特性而形成的设计模式。
具体而言,高阶组件是参数为组件,返回值为新组件的函数。


​HOC​​ 是用来将一个组件转换为另外一个组件的。


Context

​Context​​​ 设计目的是为了共享那些对于一个组件树而言是“全局”的数据。可以把 ​​Context​​​ 理解为注入数据的工具(类似于 ​​Vue​​​ 的 ​​provider​​) 。


​Context​​​ 提供了一个无需为每层组件手动添加 ​​props​​,就能在组件树间进行数据传递的方法。


我们通常在需要修改某个全局类型时使用 ​​Context​​,例如我们需要实现 换肤 效果。

官方示例

// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。
// 为当前的 theme 创建一个 context(“light”为默认值)。
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
// 使用一个 Provider 来将当前的 theme 传递给以下的组件树。
// 无论多深,任何组件都能读取这个值。
// 在这个例子中,我们将 “dark” 作为当前的值传递下去。
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}

// 中间的组件再也不必指明往下传递 theme 了。
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}

class ThemedButton extends React.Component {
// 指定 contextType 读取当前的 theme context。
// React 会往上找到最近的 theme Provider,然后使用它的值。
// 在这个例子中,当前的 theme 值为 “dark”。
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}

进阶

​React​​ 一些主流的开发技巧。


Hook


​Hook​​​ 是 ​​React 16.8​​​ 的新增特性。它可以让你在不编写 ​​class​​​ 的情况下使用 ​​state​​​ 以及其他的 ​​React​​ 特性。


​Hook​​​是 ​​React16.8​​​ 之后主流的开发利器。​​Hook​​​ 主要实现于函数组件或者自定义的​​Hook​​函数。


useState()

我们通常使用 ​​useState​​​ 来设置 ​​state​

const [state, setState] = useState(initialState);

以下使用 ​​useState​​ 的例子

const [loading, setLoading] = useState(false);

​useState​​​ 返回一个数组,数组的第一个成员是 ​​state​​​ 状态,第二个成员是设置 ​​state​​ 状态的函数。


useEffect()

useEffect(callback,[count])


​useEffect​​​ 做了什么? 通过使用这个 ​​Hook​​​,你可以告诉 ​​React​​​ 组件需要在渲染后执行某些操作。​​React​​​ 会保存你传递的函数(我们将它称之为 “effect”),并且在执行 ​​DOM​​ 更新之后调用它。


这个 ​​hook​​​ 主要是用来操作副作用的。它跟 class 组件中的 ​​componentDidMount()​​​、​​componentDidUpdate()​​​ 和 ​​componentWillUnmount()​​ 具有相同的用途。

​useEffect()​​ 有两个参数,第一个参数( 是个函数 )是用来操作副作用的,第二个参数( 是个数组、可选 )是用来约束在哪些数据更新时需要执行。


第二个参数的效果

参数情况

效果

注意事项

不传

每次渲染后都执行清理或者执行effect

这可能会导致性能问题,比如两次渲染的数据完全一样

传递空数组

只运行一次的 effect(仅在组件挂载和卸载时执行)

这就告诉 React 你的 effect 不依赖于 props 或 state 中的任何值,所以它永远都不需要重复执行

传递 [ count ]

React 将对前一次渲染的count和后一次渲染的count进行比较。若相等React 会跳过这个 effect,

实现了性能的优化

如果给第二个参数传递指定的值,可以实现一定的性能优化。具体根据实际情况来选择。它( 第二个参数 )可以控制​​setEffect​​的执行频率。


副作用

副作用指的是在完成某件事时附带执行的事。在 ​​useEffect​​​ 的基本概念中,主要的事是 ​​DOM​​ 构建,其余的就是副作用。


useContext()

const value = useContext(MyContext);


接收一个 ​​context​​​ 对象(​​React.createContext​​​ 的返回值)并返回该 ​​context​​​ 的当前值。当前的 ​​context​​​ 值由上层组件中距离当前组件最近的 ​​<MyContext.Provider>​​​ 的 ​​value​​​ ​​prop​​ 决定。


通常分两步实现使用 ​​context​

const ThemeContext = React.createContext(themes.light);
const theme = useContext(ThemeContext);

官网示例

const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};

const ThemeContext = React.createContext(themes.light);

function App() {
return (
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
);
}

function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}

function ThemedButton() {
const theme = useContext(ThemeContext);
// 会得到color: "#ffffff";background: "#222222";
return (
<button style={{ background: theme.background, color: theme.foreground }}>
I am styled by theme context!
</button>
);
}