Function Component
可使用状态Class Component
的生命周期this
指向问题伤破脑经render props
& HOC
嵌套缺陷如今开始咱们用建立一个计数器的方式开始学习使用
React Hooks
javascript
useState
的用法很简单,传入一个初始 state
,返回一个 state
以及修改 state
的函数。html
// useState 返回的 state 是个常量
// 每次组件从新渲染以后,当前 state 和以前的 state 都不相同
// 即便这个 state 是个对象
const [count, setCount] = useState(1)
复制代码
setCount
就至关于 setState
,能够传入一个新的状态或者函数。例如:java
setCount(2)
setCount(prevCount => prevCount + 1)
复制代码
其实 useState
内部能够简单理解为(只是理解):react
// 闭包存储 state 数据
function useState(initialState){
let state = initialState;
function setState = (newState, action) => {
state = newState;
}
return [state, setState]
}
复制代码
那接下来编写 Count
组件:redux
function Counter() {
const [count, setCount] = React.useState(0)
return (
<div> Count: {count} <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button> <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button> </div>
);
}
复制代码
如今咱们有了新的需求: 在 count
每次更新的时候打印 count
的值,这时咱们须要用 useEffect
来实现闭包
function Counter() {
const [count, setCount] = React.useState(0)
React.useEffect(() => {
console.log(count)
})
return (
<div> Count: {count} <button onClick={() => setCount(count + 1)}>+</button> <button onClick={() => setCount(count - 1)}>-</button> </div>
);
}
复制代码
以上在每次从新渲染时, useEffect
就能够实现打印,能够把它看成是 componentDidUpdate
和 componentDidMount
, 同于 Class Component
中的函数
componentDidMount() {
console.log(count)
}
componentDidUpdate() {
console.log(count)
}
复制代码
另外它能够返回一个函数,用于解绑一些反作用,功能相似于 componentWillUnmount
学习
React.useEffect(() => {
console.log(count)
// 注意: 当咱们每次更新计数时,都会先打印 clean 这行 log
return () => console.log('clean', count)
})
复制代码
为了防止咱们没必要要的渲染,useEffect
加入第二个参数, 只有在 count
改变的时候才会执行。优化
React.useEffect(() => {
console.log(count)
// 当咱们每次更新计数时,都会先打印 clean 这行 log
return () => console.log('clean', count)
}, [count])
复制代码
useReducer
是 useState
的替代方案,主要是为了解决多个 state
子值的问题。(会Redux
的一看就会明白)ui
看一下🌰:
// 初始化 state
const initialState = {count: 0};
// 类于 redux 的 reducer
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div> Count: {state.count} /* dispatch 调用 action 操做 */ <button onClick={() => dispatch({type: 'decrement'})}>-</button> <button onClick={() => dispatch({type: 'increment'})}>+</button> </div>
);
}
复制代码
这是个用于优化的 hook
, 返回一个 memoized 值。说白了就是会利用闭包的特性存储上次的参数,若是和此次传入的参数一致就返回以前的结果。这叫作记忆化技术。
下面咱们来看个反🌰:
function WithoutMemo() {
const [count, setCount] = useState(1);
const [val, setValue] = useState('');
function expensive() {
console.log('compute');
let sum = 0;
for (let i = 0; i < count * 100; i++) {
sum += i;
}
return sum;
}
return <div> <h4>{count}-{val}-{expensive()}</h4> <div> <button onClick={() => setCount(count + 1)}>+c1</button> <input value={val} onChange={event => setValue(event.target.value)}/> </div> </div>; } 复制代码
这个函数式组件面临的问题就是 expensive
方法无论是 count
仍是 val
改变时都会因为组件的从新渲染, 从新计算。
可是这里的昂贵计算只依赖于count
的值,在val
修改的时候,是没有必要再次计算的。在这种状况下,咱们就可使用useMemo
,只在count
的值修改时,执行expensive
计算:
// count 若是不变就不会再次执行
const expensive = React.useMemo(() => {
console.log('compute');
let sum = 0;
for (let i = 0; i < count * 100; i++) {
sum += i;
}
return sum;
}, [count]);
复制代码
useCallback
和 useMemo
很类似,不过它返回的是函数。下面继续看个🌰:
function Parent() {
const [count, setCount] = React.useState(1);
const [val, setVal] = React.useState('');
const callback = React.useCallback(() => {
return count;
}, [count]);
return <div>
<h4>{count}</h4>
// callback 做为 props 传入
<Child callback={callback}/>
<div>
<button onClick={() => setCount(count + 1)}>+</button>
<input value={val} onChange={event => setVal(event.target.value)}/>
</div>
</div>;
}
function Child({ callback }) {
const [count, setCount] = React.useState(() => callback());
React.useEffect(() => {
setCount(callback());
}, [callback]);
return (
<div>
{count}
</div>
)
}
复制代码
如今就是有一个父组件,其中包含子组件,子组件接收一个函数做为props;一般而言,若是父组件更新了,子组件也会执行更新;可是大多数场景下,更新是没有必要的,咱们能够借助useCallback来返回函数,而后把这个函数做为props传递给子组件;这样,子组件就能避免没必要要的更新。
useCallback(fn, deps) 至关于 useMemo(() => fn, deps)。
经过自定义 Hook,能够将组件逻辑提取到可重用的函数中。
自定义 Hook
是一个函数,其名称以 use
开头,函数内部能够调用其余的 Hook
。
function useConsoleCount(count) {
React.useEffect(() => {
console.log(count)
// 当咱们每次更新计数时,都会先打印 clean 这行 log
return () => console.log('clean', count)
}, [count])
}
function Counter() {
const [count, setCount] = React.useState(0);
useConsoleCount(count)
return (
<div> Count: {count} <button onClick={() => setCount(count + 1)}>+</button> <button onClick={() => setCount(count - 1)}>-</button> </div>
);
}
复制代码
hook
的使用,有错误的地方欢迎指正hook
可直接阅读官方文档