# classicHooks
以下是我们将要使用的 Hooks API,基本上都会用到:
# Hooks配方
# useLayoutEffect
这个钩子函数和useEffect相同,都是用来执行副作用。但是它会在所有的DOM变更之后同步调用effect。useLayoutEffect和useEffect最大的区别就是一个是同步一个是异步。
- useEffect,使用useEffect不会阻塞浏览器的重绘
- useLayoutEffect, 使用useLayoutEffect,会阻塞浏览器的重绘。如果你需要手动的修改Dom,推荐使用useLayoutEffect。因为如果在
useEffect中更新Dom,useEffect不会阻塞重绘,用户可能会看到因为更新导致的闪烁
# 自定义hook
# useImperativeMethods
接受一个 ref 作为参数,内部其实就是一个 useLayoutEffect 的调用。 主要就是在外部传入的 ref 上挂载内容 ,实现类似 ref 挂载到 ClassComponent 上的效果
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeMethods(ref, () : ({
focus: () : {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
2
3
4
5
6
7
8
9
10
# useCallback
- 创建一个回调方法的缓存,可以让我们传入子节点作为 props 的时候,可以让其没有变化,避免没必要的渲染。
- 根据输入的 inputs,也就是一个数组,内部的内容是否又变回,决定是返回存储的老方法,还是返回新的方法并记录。
- useCallback会返回memoized函数。当依赖项改变的时候,会返回的新的memoized函数。
import React, { useState, useCallback, useEffect } from "react";
const set = new Set();
function Callback() {
const [count, setCount] = useState(1);
const [val, setVal] = useState("");
const callback = useCallback(() => {
console.log(count);
}, [count]);
set.add(callback);
return (
<div>
<h4>{count}</h4>
<h4>{set.size}</h4>
<div>
<button onClick={() => setCount(count + 1)}>+</button>
<input value={val} onChange={event => setVal(event.target.value)} />
</div>
</div>
);
}
export default function Parent() {
const [count, setCount] = useState(1);
const [val, setVal] = useState("");
const callback = useCallback(() => {
return count;
}, [count]);
return (
<div>
<h4>{count}</h4>
<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] = useState(() => callback());
useEffect(() => {
setCount(callback());
}, [callback]);
return <div>{count}</div>;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
- useMemo 与 useCallback 类似,都是有着缓存的作用。本质的区别可能就是:一個
緩存函數、一個緩存值
# React.useRef
useRef 的作用: 获取 DOM 元素的节点 获取子组件的实例 渲染周期之间共享数据的存储(state 不能存储跨渲染周期的数据,因为 state 的保存会触发组件重渲染)
import React, { useEffect, useRef } from "react";
function App() {
const h1Ref = useRef();
useEffect(() => {
console.log("useRef");
console.log(h1Ref.current);
}, []);
return <h1 ref={h1Ref}>Hello World!</h1>;
}
export default App;
2
3
4
5
6
7
8
9
10
useEffect 里面使用到的 state 的值, 固定在了 useEffect 内部, 不会被改变,除非 useEffect 刷新,重新固定 state 的值:
有办法解决的,就是用 useRef,可以理解成 useRef 的一个作用:
就是相当于全局作用域,一处被修改,其他地方全更新...
- 普遍操作,用来操作 dom
const Hook = () => {
const [count, setCount] = useState(0);
const btnRef = useRef(null);
useEffect(() => {
console.log("use effect...");
const onClick = () => {
setCount(count + 1);
};
btnRef.current.addEventListener("click", onClick, false);
return () => btnRef.current.removeEventListener("click", onClick, false);
}, [count]);
return (
<div>
<div>{count}</div>
<button ref={btnRef}>click me </button>
</div>
);
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 如何在funtion组件中,打印出新值

# useMemo
只要父组件的状态更新,无论有没有对自组件进行操作,子组件都会进行更新,useMemo就是为了防止这点而出现的
- React 16.8.0 中发布
useMemo():useMemo 作为一个有着暂存能力的 React.memo()是判断一个函数组件的渲染是否重复执行- useMemo()是定义一段函数逻辑是否重复执行
- useMemo(() => fn, inputs)跟 useCallback(fn, inputs)效果一样
- useMemo和useCallback类似。useMemo会返回memoized值。当依赖项改变时,会重新计算memoized值。
const increase = useMemo(() => {
if(value > 2) return value + 1;
}, [value]);
]
2
3
4
const Child = memo(({ data }) => {
console.log("child render...", data.name);
return (
<div>
<div>child</div>
<div>{data.name}</div>
</div>
);
});
const Hook = () => {
console.log("Hook render...");
const [count, setCount] = useState(0);
const [name, setName] = useState("rose");
const data = useMemo(() => {
return {
name
};
}, [name]);
return (
<div>
<div>{count}</div>
<button onClick={() => setCount(count + 1)}>update count </button>
<Child data={data} />
</div>
);
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
- 首先,memo 的用法是:函数组件里面的 PureComponent
但是,如果
函数组件被 React.memo 包裹,且其实现中拥有 useState 或 useContext 的 Hook,当 context 发生变化时,它仍会重新渲染。
- 而且,
memo是浅比较,意思是,对象只比较内存地址,只要你内存地址没变,管你对象里面的值千变万化都不会触发 render
# useReducer
Redux 的核心概念是,组件发出 action 与状态管理器通信。状态管理器收到 action 以后,使用 Reducer 函数算出新的状态
- 简单来说
reducer是一个函数(state, action) => newState: 接收当前应用的 state 和触发的动作 action,计算并返回最新的 state。 - useReducer一共可以接受三个参数并返回当前的state与其配套的dispatch。
import React, { useReducer } from "react";
function reducer(state, action) {
switch (action.type) {
case "add":
return { count: state.count + 1 };
case "sub":
return { count: state.count - 1 };
default:
return state;
}
}
function Example2() {
const initialState = { count: 0 };
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>You clicked {state.count} times</p>
<button
onClick={() => {
dispatch({ type: "add" });
}}
>
add
</button>
<button
onClick={() => {
dispatch({ type: "sub" });
}}
>
sub
</button>
</div>
);
}
export default Example2;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
- useReducer的第
三个参数接受一个函数作为参数,并把第二个参数当作函数的参数执行。主要作用是初始值的惰性求值,把一些对状态的逻辑抽离出来,有利于重置state。
function init(initialCount) {
return [
...initialCount,
];
}
useReducer(reducer,[
{
id: Date.now(),
value: "Hello react"
}
],init)
2
3
4
5
6
7
8
9
10
11
12
13
# React.useEffect
# 超详细userEffect
使用 useEffect,可以直接在函数组件内处理生命周期事件。 如果你熟悉 React class 的生命周期函数,
你可以把 useEffect Hook 看做componentDidMount,componentDidUpdate和 componentWillUnmount这三个函数的组合
- 有两个参数 callback 和 dependencies 数组
- 如果 dependencies 不存在,那么 callback 每次 render 都会执行
- 如果 dependencies 存在,只有当它发生了变化, callback 才会执行
- 如果 dependencies 为
[]时,只会执行一次(请记住使用空数组的effect和componentDidMount是有差异的) - 依赖数组的问题
import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";
function useEffectTest() {
useEffect(() => {
// 默认情况下,每次渲染后都会调用该函数
console.log("render!");
// 如果要实现 componentWillUnmount,
// 在末尾处返回一个函数
// React 在该函数组件卸载前调用该方法
// 其命名为 cleanup 是为了表明此函数的目的,
// 但其实也可以返回一个箭头函数或者给起一个别的名字。
return function cleanup() {
console.log("unmounting...");
};
});
return "useEffectTest";
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
阻止每次重新渲染都会执行 useEffect 如果希望 effect 较少运行,可以提供第二个参数 - 值数组。 将它们视为该 effect 的依赖关系。 如果其中一个依赖项自上次更改后,effect 将再次运行。
const [value, setValue] = useState(0);
useEffect(() => {
// 仅在 value 更改时更新
console.log(value);
}, [value]);
2
3
4
5
6
- 如果我们之前订阅了什么,最后在
willUnMount这个生命周期里面要取消订阅,这可咋用 useEffect 实现啊:
useEffect(() => {
const subscription = 订阅全国人民吃饭的情报!
return () => {
取消订阅全国人民吃饭的情报!
}
},[])
2
3
4
5
6
大家都知道,render 了之后会执行重新 useEffect,如果 useEffect 里面有一个每 setInterval...那么每次 render 了,再次执行 useEffect 就会再创建一个 setInterval,然后就混乱了...可以把下面案例 return 的内容删掉感受下
# useEffect 的一些暗戳戳的规则
- useEffect 里面使用到的 state 的值, 固定在了 useEffect 内部, 不会被改变,除非 useEffect 刷新,重新固定 state 的值
- useEffect 不能被判断包裹
- useEffect 不能被打断
const [count, setCount] = useState(0)
useEffect(...)
return // 函数提前结束了
useEffect(...)
}
2
3
4
5
6
7
- useEffec函数参数中返回函数所代表的销毁是useEffect自己的销毁,每次重新执行函数组件都会重新生成新的Effect。假如没有销毁,由于useEffect的函数参数会在首次渲染和更新的时候调用,这就有了一致命的缺点:如果我是定义的事件,每次更新都会执行,那么岂不是在事件还没有移除掉又定义了一次,所以useEffect加入了这个功能。
# 是什么差异呢
为什么有时候在effect里拿到的是旧的state或prop呢?
这是因为javascript闭包的机制,函数组件被调用后,函数内部的state由于被内部定时器的回调所依赖,所以没有被垃圾回收机制所清除,而是保存在内存里了。所以等定时器的回掉执行时,打印的是之前闭包中存储的变量。
- 如何避免拿到旧的prop或者state?
- 使用useRef
- 查看是否遗漏了依赖, 导致effect没有更新
# 如何在useEffect中使用async/await
async函数默认会返回一个Promise对象,而useEffect中,只允许什么都不返回或者返回一个清除函数。控制台中,会触发如下警告
Warning: useEffect function must return a cleanup function or nothing. Promises and useEffect(async () => …) are not supported, but you can call an async function inside an effect..
useEffect(() => {
const fetchData = async () => {
const result = await axios('http://---');
setData(result);
}
fetchData();
}, []);
2
3
4
5
6
7
# 依赖数组的问题
string,number,undefined,null 他的值都是能够正常检测的,问题的关键还是在于
object和function
- object
- 当依赖值为 object 时,他的值引用发生变化就会触发 effect 的更新
- 但是如果只是对象里某个值变化而引用不变化,effect 依旧不会触发
- 关于 function 的试验结论:
- 如果初始值为 function, 而将其改为数字等,会触发 effect
- function 也是一个对象,当我们添加一个值在上面时,他的 effect 也不会触发
- 引用为一个新函数时,他每次都会触发;
# useEffect注意事项
- 可以使用多个useEffect分离逻辑。在class组件中,我们通常会在componentDidMount中,混杂添加事件绑定,请求数据等多种无关的逻辑。
- 如果只需要useEffect在加载时执行一次,或者卸载组件时执行一次,可以向useEffect传递一个空数组。
- useEffect不支持直接使用async函数
- 如果在useEffect中形成了闭包,将会拿到旧的props,或者state。(这个与Hook无关,与函数组件本身的特性相关)
- useEffect返回的函数,清除函数。会在上一个effect被清除时调用。
# useContext
useContext 可以实现共享状态最大的改变是可以在使用 Counter 的时候不必在包裹 Children 了,比方说我们先创建一个上下文, 这个上下文里头有一个名为 count 的 state,以及一个修改 count 的方法 setCount
React16中更新了Context API,Context主要用于爷孙组件的传值问题,新的Context API使用订阅发布者模式方式实现在爷孙组件中传值。
import React, { createContext, useState } from "react";
import { Counter } from "./Counter";
export const CountContext = createContext();
function Example2() {
const [count, setCount] = useState(0);
return (
<div>
<CountContext.Provider value={(count, setCount)}>
<Counter />
</CountContext.Provider>
</div>
);
}
export default Example2;
2
3
4
5
6
7
8
9
10
11
12
13
14
import React, { useContext} from 'react';
import {CountContext} from './Example2'
export function Counter() {
const {count,setCount} = useContext(CountContext) //一句话就可以得到count
return (
<h2>{count}</h2>
<button onClick={() => { setCount(count + 1) }}>count</button>
)
}
2
3
4
5
6
7
8
9
提示:想要通过useContext中获得存入的数据,子组件或者孙组件需要被该父组件包裹起来
# React.useState
useState 是 react 自带的一个 hook 函数,它的作用就是用来声明状态变量。
useState 这个函数接收的参数是我们的状态初始值(initial state)(只在第一次有效),
它返回了一个数组,这个数组的第[0]项是当前当前的状态值,第[1]项是可以改变状态值的方法函数。我们可以把这里的 state 看做我们在 class component 中使用的 this.state。
我们的每一次 setState 操作,在改变了值之后,都会引发 rerender 操作,从而触发页面的更新(但是如果没有改变的话,则不会触发 rerender,我们在后面将会利用这一特性做一件有趣的事情)。
更新state变量的方法,并不会像this.setState一样,合并state。而是替换state变量。
import React, { useState, useEffect } from "react";
interface Props {
value: number;
onChange: (num: number) => any;
}
export default function Counter({ value, onChange }: Props) {
const [count, setCount] = useState<number>(0);
useEffect(() => {
value && setCount(value);
}, [value]);
return [
<div key="a">{count}</div>,
<button key="b" onClick={() => onChange(count + 1)}>
点击+1
</button>
];
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React, { useState } from "react";
function Example() {
//useState的用法,分别是声明、读取、使用(修改)
const [count, setCount] = useState(0); //数组结构
const [age, setAge] = useState(18);
const [todos, setTodos] = useState([{ text: "Learn Hooks" }]);
return (
<div>
<button
onClick={() => {
setCount(count + 1);
}}
>
count
</button>
<button
onClick={() => {
setAge(age + 1);
}}
>
age
</button>
</div>
);
}
export default Example;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function MyComponent({ bigJsonData }) {
const [value, setValue] = useState(function getInitialState() {
const object = JSON.parse(bigJsonData); // expensive operation
return object.initialValue;
});
// ...
}
2
3
4
5
6
7
8
# useState函数式更新
如果新的state需要之前的state计算得到。可以向useState返回的更新函数中,传递一个函数。函数的参数是前一个state。
setValue( preValue => preValue + 1;)
# useState惰性的初始值
useState的初始值是惰性的,只会在初次渲染组件的时候起作用。如果state的初始值需用通过复杂计算得到,useState的初始值也可以是一个函数,函数的返回值将是useState的初始值。
const [value,setValue]=useState(() => {return parseInt(Math.random()*10,10)});
# react-redux@7.1.0 useSelector: 别啦 connect
const result : any = useSelector(selector : Function, equalityFn? : Function);
//就是从redux的store对象中提取数据(state)。
2
注意: 因为这个可能在任何时候执行多次,所以你要保持这个 selector 是一个纯函数。
这个 selector 方法类似于之前的connect的mapStateToProps参数的概念。并且 useSelector 会订阅 store, 当 action 被 dispatched 的时候,会运行 selector。
当然,仅仅是概念和 mapStateToProps 相似,但是肯定有不同的地方,看看 selector 和 mapStateToProps 的一些差异:
- selector 会返回任何值作为结果,并不仅仅是对象了。然后这个 selector 返回的结果,就会作为 useSelector 的返回结果。
- 当 action 被 dispatched 的时候,useSelector()将对前一个 selector 结果值和当前结果值进行浅比较。如果不同,那么就会被 re-render。 反之亦然。
- selector 不会接收 ownProps 参数,但是,可以通过闭包(下面有示例)或使用柯里化 selector 来使用 props。
使用记忆(memoizing) selector时必须格外小心(下面有示例)。- useSelector()默认使用===(严格相等)进行相等性检查,而不是浅相等(==)。
你可能在一个组件内调用 useSelector 多次,但是对 useSelector()的每个调用都会创建 redux store 的单个订阅。由于 react-reduxv7 版本使用的 react 的批量(batching)更新行为,造成同个组件中,多次 useSelector 返回的值只会 re-render 一次。
- useSelector 用于从 Redux 存储的 state 中提取值并订阅该 state,这基本上类似于在 hooks 中实现的 mapStateToProps 函数
- 首先,不再提供 ownProps API,并且应该使用 useCallback 或 useMemo 来通过自定义逻辑获取它们
- 其次,useSelector()第二个参数也是依赖数组,跟 useEffect 一样。如果不提供第二个参数每次组件更新时都会重新计算;如果提供了依赖数组,只有依赖数组对应的值变更了之后,才会触发重新计算
- 除此之外,redux 以前的性能优化逻辑同样保留了下来,如果当前的 props 跟老的 props 相同,则组件将不会重新渲染。
- 由于 React redux 中使用的批处理更新的逻辑,导致同一组件中的多个 useSelector()重新计算出 state,只会让组件重新渲染一次。因此,我们可以自由的在组件中 useSelector(),而不用担心重复渲染的情况
- 在下面的例子中,我们可以将单个 useSelector()分成两个独立的(一个读取 title,另一个读取 content)useSelector()他们在性能和渲染数量方面完全相同
import React from 'react';
import { useSelector } from 'react-redux';
const Component = props => {
const { title, content } = useSelector(state => ({
title: state.title,
content: state.content
}));
return <div title={title}>{content}</div>;
2
3
4
5
6
7
8
9
# 相等比较和更新
当函数组件渲染时,会调用提供的 selector 函数,并且从 useSelector 返回其结果。(如果 selector 运行且没有更改,则会返回缓存的结果)。
从v7.1.0-alpha.5开始,默认比较是严格比较(===)。这点于 connect 的时候不同,connect 使用的是浅比较。这对如何使用 useSelector()有几个影响。
使用 mapState,所有单个属性都在组合对象中返回。返回的对象是否是新的引用并不重要 - connect()只比较各个字段。使用 useSelector 就不行了,默认情况下是,如果每次返回一个新对象将始终进行强制 re-render。如果要从 store 中获取多个值,那你可以这样做:
- useSelector()调用多次,每次返回一个字段值。
- 使用
Reselect或类似的库创建一个记忆化(memoized) selector,它在一个对象中返回多个值,但只在其中一个值发生更改时才返回一个新对象。 - 使用 react-redux 提供的
shallowEqual函数作为useSelector的equalityFn参数。
import { shallowEqual, useSelector } from "react-redux";
// later
const selectedData = useSelector(selectorReturningObject, shallowEqual);
2
3
# useSelector 例子
import React from "react";
import { useSelector } from "react-redux";
export const CounterComponent = () => {
const counter = useSelector(state => state.counter);
return <div>{counter}</div>;
};
2
3
4
5
6
7
通过闭包使用props来确定要提取的内容
import React from "react";
import { useSelector } from "react-redux";
export const TodoListItem = props => {
const todo = useSelector(state => state.todos[props.id]);
return <div>{todo.text}</div>;
};
2
3
4
5
6
7
# 使用记忆化_memoizing_selector
当使用如上所示的带有
内联selector的useSelector时,如果渲染组件,则会创建 selector 的新实例。只要 selector 不维护任何状态,这就可以工作。但是,记忆化(memoizing) selectors 具有内部状态,因此在使用它们时必须小心。
当selector仅依赖于状态时,只需确保它在组件外部声明,这样一来,每个渲染所使用的都是相同的选择器实例:
import React from "react";
import { useSelector } from "react-redux";
import { createSelector } from "reselect"; //上面提到的reselect库
const selectNumOfDoneTodos = createSelector(
state => state.todos,
todos => todos.filter(todo => todo.isDone).length
);
export const DoneTodosCounter = () => {
const NumOfDoneTodos = useSelector(selectNumOfDoneTodos);
return <div>{NumOfDoneTodos}</div>;
};
export const App = () => {
return (
<>
<span>Number of done todos:</span>
<DoneTodosCounter />
</>
);
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
如果selector依赖于组件的props,但是只会在单个组件的单个实例中使用,则情况也是如此:
import React from "react";
import { useSelector } from "react-redux";
import { createSelector } from "reselect";
const selectNumOfTodosWithIsDoneValue = createSelector(
state => state.todos,
(_, isDone) => isDone,
(todos, isDone) => todos.filter(todo => todo.isDone === isDone).length
);
export const TodoCounterForIsDoneValue = ({ isDone }) => {
const NumOfTodosWithIsDoneValue = useSelector(state =>
selectNumOfTodosWithIsDoneValue(state, isDone)
);
return <div>{NumOfTodosWithIsDoneValue}</div>;
};
export const App = () => {
return (
<>
<span>Number of done todos:</span>
<TodoCounterForIsDoneValue isDone={true} />
</>
);
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
但是,如果selector被用于多个组件实例并且依赖组件的props,那么你需要确保每个组件实例都有自己的 selector 实例
import React, { useMemo } from "react";
import { useSelector } from "react-redux";
import { createSelector } from "reselect";
const makeNumOfTodosWithIsDoneSelector = () =>
createSelector(
state => state.todos,
(_, isDone) => isDone,
(todos, isDone) => todos.filter(todo => todo.isDone === isDone).length
);
export const TodoCounterForIsDoneValue = ({ isDone }) => {
const selectNumOfTodosWithIsDone = useMemo(
makeNumOfTodosWithIsDoneSelector,
[]
);
const numOfTodosWithIsDoneValue = useSelector(state =>
selectNumOfTodosWithIsDoneValue(state, isDone)
);
return <div>{numOfTodosWithIsDoneValue}</div>;
};
export const App = () => {
return (
<>
<span>Number of done todos:</span>
<TodoCounterForIsDoneValue isDone={true} />
<span>Number of unfinished todos:</span>
<TodoCounterForIsDoneValue isDone={false} />
</>
);
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# useSelector 性能
前面说了,selector 的值改变会造成 re-render。但是这个与 connect 有些不同,useSelector()不会阻止组件由于其父级 re-render 而 re-render,即使组件的 props 没有更改。
如果需要进一步的性能优化,可以在 React.memo()中包装函数组件:
const CounterComponent = ({ name }) => {
const counter = useSelector(state => state.counter);
return (
<div>
{name}: {counter}
</div>
);
};
export const MemoizedCounterComponent = React.memo(CounterComponent);
2
3
4
5
6
7
8
9
10
# useDispatch()
const dispatch = useDispatch();
//这个Hook返回Redux store中对dispatch函数的引用。你可以根据需要使用它。
2
import React from "react";
import { useDispatch } from "react-redux";
export const CounterComponent = ({ value }) => {
const dispatch = useDispatch();
return (
<div>
<span>{value}</span>
<button onClick={() => dispatch({ type: "increment-counter" })}>
Increment counter
</button>
</div>
);
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
当使用dispatch将回调传递给子组件时,建议使用useCallback对其进行记忆,否则子组件可能由于引用的更改进行不必要地呈现。
import React, { useCallback } from "react";
import { useDispatch } from "react-redux";
export const CounterComponent = ({ value }) => {
const dispatch = useDispatch();
const incrementCounter = useCallback(
() => dispatch({ type: "increment-counter" }),
[dispatch]
);
return (
<div>
<span>{value}</span>
<MyIncrementButton onIncrement={incrementCounter} />
</div>
);
};
export const MyIncrementButton = React.memo(({ onIncrement }) => (
<button onClick={onIncrement}>Increment counter</button>
));
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# useStore
const store = useStore();
//这个Hook返回redux <Provider>组件的store对象的引用。
2
这个钩子应该不常被使用。useSelector 应该作为你的首选。但是,有时候也很有用。来看个例子:
import React from "react";
import { useStore } from "react-redux";
export const CounterComponent = ({ value }) => {
const store = useStore();
// 仅仅是个例子! 不要在你的应用中这样做.
// 如果store中的state改变,这个将不会自动更新
return <div>{store.getState()}</div>;
};
2
3
4
5
6
7
8
9
10
# Hooks 配方
# useActions
这个是 alpha 的一个 hook,但是在 alpha.4 中听取 Dan 的建议被移除了。
# useShallowEqualSelector
import { shallowEqual } from "react-redux";
export function useShallowEqualSelector(selector) {
return useSelector(selector, shallowEqual);
}
2
3
4
5