-
Initialization (初始化阶段:组件实例的创建) -
constructor()
:在加载阶段前调用一次,可以初始化state,接受两个参数:props 和 context; -
Mounting (加载阶段:组件插入 dom中) -
componentWillMount()
、render()-创建虚拟 dom,并进行 diff 算法
、componentDidMount()-可进行网络请求,组件挂载完成
-
Updating (更新阶段:属性或状态每改变一次都将会触发一次,组件重新渲染。) -
componentWillUpdate()、componentDidUpdate()
-
Unmounting (卸载阶段:组件卸载和销毁) -
componentWillUnmount()
-
Error Handling(错误处理) -
componentDidCatch()
-
新增了
getDerivedStateFromProps()
、getSnapshotBeforeUpdate()
来代替弃用的三个钩子函数(componentWillMount、componentWillReceiveProps,componentWillUpdate)
https://www.cnblogs.com/ygunoil/p/12692330.html
http://www.ruanyifeng.com/blog/2016/04/cors.html
https://www.jianshu.com/p/d600f749bb19
React Hooks
React Hooks 的意思是,组件尽量写成纯函数
,如果需要外部功能和副作用,就用钩子把外部代码"钩"进来。而React Hooks 就是我们所说的“钩子”。
Hooks 本质是把面向生命周期编程
变成了面向业务逻辑编程
,它能够让函数组件也拥有 状态和生命周期 的特性,从而可以不用再去关心本不该关心的生命周期。使得函数组件的功能更加实在,更加方便我们在业务中实现业务逻辑代码的分离和组件的复用。
·useState() ·userContext() · userReducer() ·useEffect()
文档中的 “动机” 就很好的解释了为什么 React 要加入 Hooks 特性,总结来说就是三个基本要素(why?):
- 1:组件之间的逻辑状态难以复用;
- 2:大型复杂的组件很难拆分;
- 3:Class 语法的使用不友好;
总的来说,实际上就是类组件在多年的应用实践中,发现了很多无法避免问题而又难以解决,而相对类组件,函数组件又太过于简陋,比如,类组件可以访问生命周期方法,函数组件不能;类组件中可以定义并维护 state(状态),而函数组件不可以;类组件中可以获取到实例化后的 this,并基于这个 this 做各种各样的事情,而函数组件不可以;
在开发中,函数式编程方式在JS中确实比 Class 的面向对象方式更加友好直观,那么只要能够将函数的组件能力补齐,那么这些问题也就迎刃而解了。
(一)useState() - 状态钩子:
useState() 它接受状态的初始值作为参数,即下例中计数的初始值,它返回一个数组,其中数组第一项为一个变量,指向状态的当前值
。类似 this.state, 第二项是一个函数(func()),用来更新状态
, 类似 setState;
-
useState() 主要作用就是给函数组件赋予状态(State),使用函数组件再也不用关心 super(props) 和 this 指针问题;
-
|
*-* 注意 :
state中保留的最好是 会影响渲染的数据,如果只是想要一个类似 实例数据持久化,那么请使用 useRef; -
<React.Fragment>
可以所缩写为一对空标签;
import React, { useState } from 'react'
const AddCount = () => {
// 【1】
const [ count, setCount ] = useState(0)
const [ obj, setObj ] = useState({name: 'didi'})
// 【2】
const addcount = () => {
let newCount = count
setCount(newCount += 1)
}
const addObj = () => {
// 添加新属性,需要是新对象
setObj({
...obj,
age: 18,
})
}
return (
<>
<p>{count}</p>
<button onClick={addcount}>count++</button>
</>
)
}
export default AddCount
(二)useEffect() - 副作用钩子:
可以把 useEffect Hook 看做 componentDidMount() -挂载完成
,componentDidUpdate() -组件更新
和 componentWillUnmount() -组件销毁
这三个生命周期函数的组合,是个无阻塞更新;
useEffect() 接受两个参数,第一个参数 是你要进行的异步操作(回调函数)
,第二个参数 是一个数组
,用来给出 Effect 的依赖项
。
- 当 第2个参数 省略不填时,useEffect 会在每次组件渲染时执行。类似于类组件的
componentDidMount 生命周期
,每次数据更新都会执行; - useEffect 还可以通过让函数返回一个函数来进行一些取消兼容之类的清理操作,比如取消订阅等;
import React, { useState } from 'react'
const AddCount = () => {
const [width, setWidth] = useState(window.innerWidth);
// 【1】组件挂载完成之后执行 && 组件数据更新完成之后执行, 第2个参数为空 ===> componentDidMount (mount时)
useEffect(() => {
const handleResize = ()=>{
setWidth(window.innerWidth);
}
window.addEventListener('resize', handleResize);
})
// 【2】组件挂载完成之后执行,第2个参数为空数组则不监听全部状态,只执行1次 ===> componentDidUpdate (update更新)
useEffect(() => {
console.log(678)
}, [])
// 【3】组件被卸载之前执行 (引入react-dom进行卸载测试) ===> componentWillUnmount (unmount时)
useEffect(() => {
return () => {
// 取消监听窗口的宽度变化
window.removeEventListener('resize');
}
});
// ✅ better 请求
useEffect(() => {
// 请求体
(async () => {
const { data } = await ajax(params);
// todo
})();
}, [width]);
return (
<>
<p>window width is {width}</p>
</>
)
}
export default AddCount
(三)useContext() - 组件传值,共享状态钩子:
在React16.X以后支持,避免了 react 逐层通过 Props 传递数据。
createContext()
-创建父组件容器,需要共享数据的组件用"Provider" 包裹
,利用"参数 value"
进行传值,这里value是一个对象,传值可自定义;useContext()
- 钩子函数用来引入 Context 对象,从中父组件属性中的值;
import React,{ useContext } from 'react'
const Ceshi = () => {
// 【1】创建父组件容器
const AppContext = React.createContext({})
const A =() => {
const { name } = useContext(AppContext)
return (
<p>我是A组件的名字:{name},<span>我是A的子组:件{name}</span></p>
)
}
const B =() => {
const { name } = useContext(AppContext)
return (
<p>我是B组件的名字:{name}</p>
)
}
// 挂载组件
return (
// 使用 AppContext.Provider 提供的Context对象,这个对象可以被子组件共享
<AppContext.Provider value={{name: 'hook测试'}}>
<A />
<B />
</AppContext.Provider>
)
}
export default Ceshi
(四)useReducer() - action 钩子,状态管理
Redux 的核心概念是,组件发出 action 与状态管理器通信。状态管理器收到 action 以后,使用 Reducer 函数算出新的状态,Reducer 函数的形式是(state, action) => newState。
- 它接受 Reducer 函数和状态的初始值作为参数,返回一个数组。数组的第一个成员是状态的当前值,第二个成员是发送 action 的dispatch函数。
import { useReducer } from 'react';
const initialState = {
number: 0
};
const myReducer = (state, action) => {
switch (action.type) {
case 'add':
return { ...state, number: state.number + 1 };
case 'minus':
return { ...state, number: state.number - 1 };
default:
return state;
}
};
const Count = () => {
const [state, dispath] = useReducer(myReducer, initialState);
return (
<div>
<div>{state.number}</div>
<button onClick={() => dispath({ type: 'add' })}>add</button>
<button onClick={() => dispath({ type: 'minus' })}>minus</button>
</div>
);
};
export default Count;