Open brunoyang opened 5 years ago
在v7.1中,react-redux加上了hooks,接下来我们就来看看新hooks,以及需要如何修改组件。 如果你还不清楚什么是hooks,建议阅读此文档。
签名:
const result : any = useSelector(selector : Function, equalityFn? : Function)
举例来说:
import { shallowEqual, useSelector } from 'react-redux' const count = useSelector(stoer => store.count, shallowEqual); // 第二个参数可选,也可以换成自定义的比较函数
用法很简单
const dispatch = useDispatch; dispatch({ type: 'action1' })
import React from 'react'; import { connect } from 'react-redux'; function componentWithConnect({ count, addCount }) { return ( <> <span>{count}</span> <button onClick={addCount}>点击</button> </> ); } const mapStateToProps = (store) => ({ count: store.count, }); const mapDispatch = (dispatch) => ({ addCount: () => dispatch({ type: 'addCount' }), }); export default connect(mapStateToProps, mapDispatch)(componentWithConnect);
import React from 'react'; import { useSelector, useDispatch } from 'react-redux'; export default function componentWithHooks() { const { count } = useSelector(store => ({ count: store.count, })); const dispatch = useDispatch(); const addCount = () => dispatch({ type: 'addCount' }); return ( <> <span>{count}</span> <button onClick={addCount}>点击</button> </> ); }
在新组件中,我们去掉了connect,使用了useSelector和useDispatch两个hooks。这样就不用再从props传入,让逻辑更为内聚。(另外还有一个好处就是在React Devtools里也少了一层嵌套)
useSelector
useDispatch
可能有的同学会有疑问,useDispatch并没有完全代替mapDispatchToProps,为什么不加上useActions呢? 实际上在beta版本中,react-redux是带有useActions的,但在dan的建议下,去掉了这个api。为什么呢?其实只要自己模拟一下,你就能知道为什么了。
function someComponet() { // !!!!没有 useActions 这个api!!!! const actions = useActions((dispatch) => ({ action1: () => dispatch({ type: 'action1' }), action2: () => dispatch({ type: 'action2' }), })); useEffect(() => { actions.action1(); actions.action2(); }, [actions.action1, actions.action2]); }
看看为了发送一个dispatch,写了多少模板代码,要是有更多的action,useEffect的依赖列表就会变得更长。此外,在得到actions后,几乎是立即就又被解包了,在使用connect的情况下可能还是可以接受的,但在使用了hooks后,无疑是画蛇添足。 其实在过去,通过mapDispatchToProps将() => dispatch({ type: 'action1' })包装成一个actionCreator,是不是有过分迷恋这种『一行缩写』的嫌疑呢?更不要说这种缩写会让阅读代码的人搞不清数据流。 我们再来看如果直接使用useDispatch是怎么样的
mapDispatchToProps
() => dispatch({ type: 'action1' })
function someComponet() { const dispatch = useDispatch(); useEffect(() => { dispatch({ type: 'action1' }); dispatch({ type: 'action2' }); }, [dispatch]); }
是不是更简单,也更清晰了呢。
在很多情况下,useDispatch已经够用,但在一些复杂情况下,还是需要自定义hooks的。如要在多个组件间共享逻辑,自定义hooks是个不错的选择。
// complexActions.js const complexActions = () => { const dispatch = useDispatch(); dispatch({ type: 'actions1' }); dispatch({ type: 'actions2' }); someRequest().then(() => { dispatch({ type: 'actions3' }); }); // balbala... }; // componetA.js function componentA() { useEffect(() => { complexActions(); }, [complexActions]); return (...); } // componetB.js function componentB() { useEffect(() => { complexActions(); }, [complexActions]); return (...); }
触发dispatch后,useSelector被触发(因为useSelector是使用useEffect实现,useEffect的依赖就有store),当发现前后两次state不一样时,会触发重渲染。此时的问题是当不相关的值被修改,本组件仍然会重渲染。可以使用reselect来减少这种情况,具体怎么做,可以参考官方文档。 另外,connect也会对props做一次浅比较,防止重渲染。所以去掉connect之后,就需要使用React.memo去做了。
React.memo
import React from 'react'; function componentA(props) { return <>...</> } export default React.memo(componentA);
—_—
在v7.1中,react-redux加上了hooks,接下来我们就来看看新hooks,以及需要如何修改组件。 如果你还不清楚什么是hooks,建议阅读此文档。
hooks
useSelector
签名:
举例来说:
useDispatch
用法很简单
使用connect的写法
换成hooks的写法
在新组件中,我们去掉了connect,使用了
useSelector
和useDispatch
两个hooks。这样就不用再从props传入,让逻辑更为内聚。(另外还有一个好处就是在React Devtools里也少了一层嵌套)消失的useActions?
可能有的同学会有疑问,useDispatch并没有完全代替mapDispatchToProps,为什么不加上useActions呢? 实际上在beta版本中,react-redux是带有useActions的,但在dan的建议下,去掉了这个api。为什么呢?其实只要自己模拟一下,你就能知道为什么了。
看看为了发送一个dispatch,写了多少模板代码,要是有更多的action,useEffect的依赖列表就会变得更长。此外,在得到actions后,几乎是立即就又被解包了,在使用connect的情况下可能还是可以接受的,但在使用了hooks后,无疑是画蛇添足。 其实在过去,通过
mapDispatchToProps
将() => dispatch({ type: 'action1' })
包装成一个actionCreator,是不是有过分迷恋这种『一行缩写』的嫌疑呢?更不要说这种缩写会让阅读代码的人搞不清数据流。 我们再来看如果直接使用useDispatch是怎么样的是不是更简单,也更清晰了呢。
自定义hooks
在很多情况下,useDispatch已经够用,但在一些复杂情况下,还是需要自定义hooks的。如要在多个组件间共享逻辑,自定义hooks是个不错的选择。
性能优化建议
触发dispatch后,useSelector被触发(因为useSelector是使用useEffect实现,useEffect的依赖就有store),当发现前后两次state不一样时,会触发重渲染。此时的问题是当不相关的值被修改,本组件仍然会重渲染。可以使用reselect来减少这种情况,具体怎么做,可以参考官方文档。 另外,connect也会对props做一次浅比较,防止重渲染。所以去掉connect之后,就需要使用
React.memo
去做了。参考