有感这篇文章👉函数式编程看React Hooks(二)事件绑定反作用深度剖析,做者写得条理很清晰。react
在此再强调一遍: 为何要用useCallback去缓存onMouseMove这个函数?由于该函数是一个useEffect的依赖项,并且它是个引用类型的值,因此每一次re-render都会是新的函数。假若该函数未发生变化,其实没有必要每次re-render都生成新的,这也是useCallbak最主要的做用。编程
下面延伸一丢丢,仍是讲hooks的依赖项。从我本身还原的部分HashRouter代码讲起:缓存
export default function HashRouter(props) {
let locationState = null;
const [location, setlocation] = useState({
pathname: window.location.hash.slice(1) || "/",
state: locationState
});
const handleHashChange = useCallback(() => {
console.log('执行 useCallback里面的函数') // 只要hashchange就会执行
setlocation({
...location,
pathname: window.location.hash.slice(1), // 新pathname的值并无依赖上一个pathname
state: locationState
})
}, []); // 这里并无添加依赖
useEffect(() => {
console.log('执行useEffect函数') // 只会打印一次
window.addEventListener('hashchange', handleHashChange)
return () => {
window.removeEventListener('hashchange', handleHashChange)
}
}, []); // 这里也没有添加依赖
const val = {
location,
history: {
push: to => {
if (typeof to === 'object') {
let {
pathname,
state
} = to;
window.location.hash = pathname;
locationState = state;
} else {
window.location.hash = to;
}
}
}
}
return <ReactRouterContext.Provider value={val}>
{
props.children
}
</ReactRouterContext.Provider>
}
复制代码
请看代码中的注释部分。是的,我在上述useCallback和useEffect中都没有添加依赖项。其实这是很差的,会形成疑惑和不解。ide
但另外一方面,它实现了缓存函数&&只绑定一次hashchange事件&&在hashchange时正常切换页面的设计初衷:函数式编程
当我一开始对比文章开头引用的文章和本身这段代码时,也感到疑惑,再仔细去筛查,发现:在setlocation时,是从外部获取新值的这个缘由促成的。因此才可以实现依赖项为空,且照样能刷新的目的。函数
下面咱们引入一组对照组,就能够发现确实如此:post
export default function HashRouter(props) {
let locationState = null;
const [location, setlocation] = useState({
pathname: window.location.hash.slice(1) || "/",
state: locationState
});
const [count, setcount] = useState({ // +++++ 新增这一段 +++++
number: 0
})
const handleHashChange = useCallback(() => {
setcount({
number: count.number+1 // +++++ 新增这一段 +++++
});
setlocation({
...location,
pathname: window.location.hash.slice(1),
state: locationState
})
}, []);
useEffect(() => {
window.addEventListener('hashchange', handleHashChange)
return () => {
window.removeEventListener('hashchange', handleHashChange)
}
}, []);
console.log('count--------', count); // +++++ 新增这一段 +++++ //会发现count只会增长到1,由于react的比较是Object.is!无论是primitive仍是引用类型的值
console.log('location', location); // +++++ 新增这一段 +++++
// 这个之因此会变化,是由于它的计算,是从window.location.hash中设置新值的,而不是依赖前一个值
const val = {
location,
history: {
push: to => {
if (typeof to === 'object') {
let {
pathname,
state
} = to;
window.location.hash = pathname;
locationState = state;
} else {
window.location.hash = to;
}
}
}
}
return <ReactRouterContext.Provider value={val}>
{
props.children
}
</ReactRouterContext.Provider>
}
复制代码
再看看执行这段代码的打印结果:spa
这个结果就和上面推荐的文章的结果相同了。设计