react组件分为如下几种:vue
一、功能组件(无状态组件)react
Functional (Stateless) Component,功能组件也叫无状态组件,通常只负责渲染。redux
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
复制代码
二、类组件(有状态组件)
Class (Stateful) Component,类组件也是有状态组件,也能够叫容器组件。通常有交互逻辑和业务逻辑。数组
class Welcome extends React.Component {
state = {
name: ‘tori’,
}
componentDidMount() {
fetch(…);
…
}
render() {
return (
<> <h1>Hello, {this.state.name}</h1> <button onClick={() => this.setState({name: ‘007’})}>更名</button> </>
);
}
}
复制代码
三、渲染组件 Presentational Component,和功能(无状态)组件相似。浏览器
const Hello = (props) => {
return (
<div> <h1>Hello! {props.name}</h1> </div>
)
}
复制代码
Hook 出现以前,组件之间复用状态逻辑很难,解决方案(HOC、Render Props)都须要从新组织组件结构, 且代码难以理解。在React DevTools 中观察过 React 应用,你会发现由 providers,consumers,高阶组件,render props 等其余抽象层组成的组件会造成“嵌套地狱”。
组件维护愈来愈复杂,譬如事件监听逻辑要在不一样的生命周期中绑定和解绑,复杂的页面componentDidMount包涵不少逻辑,代码阅读性变得不好。
class组件中的this难以理解,且class 不能很好的压缩,而且会使热重载出现不稳定的状况。更多引子介绍参见官方介绍。
因此hook就为解决这些问题而来:缓存
useState 是 React Hooks 中很基本的一个 API,它的用法主要有这几种:性能优化
1. const [ count1, setCount1 ] = useState(0);
1. const [ count2, setCount2 ] = useState(() => 0);
1. setCount1(1); // 修改 state
复制代码
class this.setState更新是state是合并, useState中setState是替换。markdown
useState 和 class state 的区别 虽然函数组件也有了 state,可是 function state 和 class state 仍是有一些差别:闭包
关于第2点,举个例子less
在第一个例子中,连续点击十次,页面上的数字会从0增加到10。而第二个例子中,连续点击十次,页面上的数字只会从0增加到1
class 组件里面能够经过 this.state 引用到 count,因此每次 setTimeout 的时候都能经过引用拿到上一次的最新 count,因此点击多少次最后就加了多少。
在 function component 里面每次更新都是从新执行当前函数,也就是说 setTimeout 里面读取到的 count 是经过闭包获取的,而这个 count 实际上只是初始值,并非上次执行完成后的最新值,因此最后只加了1次。
要解决上面这个问题,就须要使用useRef,useRef是一个对象,他拥有一个current属性,而且无论函数组件执行多少次,useRef返回的对象永远都是原来的那一个
useRef 有下面这几个特色:
useRef
是一个只能用于函数组件的方法。useRef
是除字符串 ref
、函数 ref
、createRef
以外的第四种获取 ref
的方法。useRef
在渲染周期内永远不会变,所以能够用来引用某些数据。ref.current
不会引起组件从新渲染。useEffect
是一个 Effect Hook
,经常使用于一些反作用的操做,在必定程度上能够充当 componentDidMount
、componentDidUpdate
、componentWillUnmount
这三个生命周期。useEffect
是很是重要的一个方法,能够说是 React Hooks 的灵魂,它用法主要有这么几种:
useEffect
接收两个参数,分别是要执行的回调函数、依赖数组。componentDidMount
)执行,返回的函数会在组件卸载时(componentWillUnmount
)执行。componentDidMount
和 componentDidUpdate
)执行。useEffect 比较重要,它主要有这几个做用:
useLayoutEffect 也是一个 Hook 方法,从名字上看和 useEffect 差很少,他俩用法也比较像。在90%的场景下咱们都会用 useEffect,然而在某些场景下却不得不用 useLayoutEffect。useEffect 和 useLayoutEffect 的区别是:
例如咱们使用useEffect方法来更新Demo的位置,那么在页面渲染时,咱们就会看到Demo原来的位置,而后这个时候useEffect方法才会执行,更新Demo的位置,咱们就会在页面上看到Demo位置的变化,可是有的时候咱们不想让用户看到这个变化的过程,会比较丑,好比变动一个元素的位置,就会变成闪现过去,这个时候就须要使用useLayoutEffect
跨组件共享数据的钩子函数
const value = useContext(MyContext);
// MyContext 为 context 对象(React.createContext 的返回值)
// useContext 返回MyContext的返回值。
// 当前的 context 值由上层组件中距离当前组件最近的<MyContext.Provider> 的 value prop 决定。
复制代码
useContext 的组件总会在 context 值变化时从新渲染, 因此<MyContext.Provider>包裹的越多,层级越深,性能会形成影响。 <MyContext.Provider>的value 发生变化时候,包裹的组件不管是否订阅content value,全部组件都会从新渲染。
const [state, dispatch] = useReducer(reducer, initialState);
复制代码
reducer就是一个只能经过action将state从一个过程转换成另外一个过程的纯函数;
useReducer就是一种经过(state,action) => newState的过程,和redux工做方式同样。 数据流: dispatch(action) => reducer更新state => 返回更新后的state
官方推荐如下场景须要useReducer更佳:
使用reducer有助于将读取与写入分开。
useMemo 的用法相似 useEffect,经常用于缓存一些复杂计算的结果。useMemo 接收一个函数和依赖数组,当数组中依赖项变化的时候,这个函数就会执行,返回新的值。
const sum = useMemo(() => {
// 一系列计算
}, [count])
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);; 返回一个 memoized 值,和useCallback同样,当依赖项发生变化,才会从新计算 memoized 的值。useMemo和useCallback不一样之处是:它容许你将memoized应用于任何值类型(不只仅是函数)。
复制代码
DatePicker 组件每次打开或者切换月份的时候,都须要大量的计算来算出当前须要展现哪些日期。而后再将计算后的结果渲染到单元格里面,这里可使用 useMemo 来缓存,只有当传入的日期变化时才去计算。
和 useMemo 相似,只不过 useCallback 是用来缓存函数。
const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], );
//返回一个 memoized 回调函数。
复制代码
总结: useCallback将返回一个记忆的回调版本,仅在其中一个依赖项已更改时才更改。当将回调传递给依赖于引用相等性的优化子组件以防止没必要要的渲染时,此方法颇有用。使用回调函数做为参数传递,每次render函数都会变化,也会致使子组件rerender, useCallback能够优化rerender。