关于hooks,你该知道的
Posted 前端e站
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于hooks,你该知道的相关的知识,希望对你有一定的参考价值。
关于hooks使用,你该知道的,可以看看
首先,还是拿第一个hook例子来说。
const count=useCounter()
//别的地方调用了这个hook
function useCounter()
console.log('调用了count')
// 这里是每次都打印出来的
const [count,setCount]=useState(0)
// useEffect(()=>
// setInterval(() =>
// console.log('useCounter',count)
// setCount(count + 1);
// , 1000);
// ,[])
// 这里的count取的是初始执行这个useEffect时候的值,
// 也就是0,所以每次加计算的都是从0开始,
// 所以这里的值应该会一直是0
// useEffect(()=>
// let id=setInterval(() =>
// console.log('useCounter',count)
// setCount(count + 1);
// , 1000);
// ,[count])
// 每次重新执行,setInterval都是会重新定义,
// 所以需要一个全局变量来保存这个东西,比如用一个ref来保存,
// 或者使用函数模式设置count
useEffect(()=>
let id=setInterval(() =>
console.log('useCounter',count)
setCount(c=>c+1);
, 1000);
// 不需要传入依赖,只执行一次,setInterval不会重置,
// setCount的函数设置方式,可以实现我们的效果
,[])
// 或者全局挂在一个ref上面
return [count]
可以看出,hook的每一次渲染都会走到hook里面。
-
这个里面好像是因为count值会变化,外面引用到了,所以每次都会重新渲染useCounter这个函数。
-
但是这个里面的useEffect其实只会调用一次。
每一次渲染都有自己的事件处理函数,包括传入的参数
-
我们的组件函数每次渲染都会被调用,每次调用的count都是常量,并且他被赋予了当前渲染中的状态值,所以才会有如果函数依赖外面的参数,就要把参数传入到第二个参数里面,当参数发生变化就让这个函数重新创建一遍。
-
每一次渲染都有一个“新版本”的handleClick,每一个版本的handleClick都记住了自己的event。
-
vue更像是把所有数据都存在一个地方,每次用到参数的时候都去那里找当前最新的,这个函数一旦定义好就不变了。
-
在任意一次的渲染中,props和state始终是不变的,props和state在不同的渲染中是相互独立的,所以使用到他们的任意值也都是相互独立的,他们都属于一次特定的渲染。即使事件处理中的异步函数调用“看到”的也是这次渲染中的值。也有可能不是最新的值。
effect:每次渲染都有他自己的effects
-
并不是count值在“不变”的effect中发生了改变,而是effect函数本身在每一次渲染中都不同,如果effect依赖于外部的count值,那么每一个版本的effect应该都是根据最新的count来创建的。
-
虽然effect是一个,但是每次渲染都是一个不同的函数,并且每个effect函数得到的props,或者state都来自属于他的那次特定渲染。
-
effect渲染的时间。
function Counter()
// ...
useEffect(
// Effect function from first render
() =>
document.title = `You clicked $0 times`;
);
// ...
// 渲染状态为 0时候的UI。
// 需要渲染的内容: <p>You clicked 0 times</p>。
// 渲染完了之后调用这个
// () => document.title = 'You clicked 0 times' 。
// 开始更新UI,给DOM添加一些东西。
// 绘制到屏幕上。
// 运行给我的effect
// 运行 () => document.title = 'You clicked 0 times' 。
// 初次渲染
function Counter()
// ...
useEffect(
// Effect function from second render
() =>
document.title = `You clicked $1 times`;
);
// ...
// React: 渲染状态为 1时候的UI。
// 需要渲染的内容: <p>You clicked 1 times</p>。
// 渲染完了之后调用
// effect:() => document.title = 'You clicked 1 times' 。
// 开始更新UI,修改了DOM。
// 更改绘制到屏幕上了。
// 运行渲染effect
// 运行 () => document.title = 'You clicked 1 times' 。
function Counter()
// ...
useEffect(
// Effect function from third render
() =>
document.title = `You clicked $2 times`;
);
// ..
1 .所有effects都会在渲染之后依次执行,概念上他只是组件输出的一部分,并且可以看到某次特定渲染的props和state。
2 .和这个不同的是之前的this.state.count,这种模式,只是会获取到最新的数据。
effect清理上次的函数
// 错误的认识:
// 假设第一次渲染的时候props是id: 10,
// 第二次渲染的时候是id: 20
// 清除了 id: 10的effect。
// 渲染id: 20的UI。
// 运行id: 20的effect
// 正确的
// 渲染id: 20的UI。
// 屏幕上可以看到id: 20的UI。
// 清除id: 10的effect。
// 运行id: 20的effect。
// effect的清除并不会读取最新的props,
// 他只能读取到定义他的那次渲染的props值
-
react会根据我们当前的props,state同步到DOM。
-
useEffect使你能够根据props和state同步react tree之外的东西。
-
react并不能区分effects的不同,所以为了避免不重复的调用,可以给useEffect一个依赖数组参数。
useEffect(() =>
document.title = 'Hello, ' + name;
, [name]); // Our deps
// 保证只使用了渲染中的name
// 如果当前渲染中的这些依赖项和上一次运行这个effect的时候值一样,
// 因为没有什么需要同步React会自动跳过这次effect:
-
即使依赖数组中只有一个值在两次渲染中不同,也不会跳过effect的运行,会同步所有
移除依赖的常见方式
1. 让Effect自给自足,但是这种使用场景及其优先。放弃了外面修改state的权力。
useEffect(() =>
const id = setInterval(() =>
setCount(count + 1);
, 1000);
return () => clearInterval(id);
, [count]);
useEffect(() =>
const id = setInterval(() =>
setCount(c => c + 1);
, 1000);
return () => clearInterval(id);
, []);
2. 使用reducer,解耦行为和操作数据的两个过程。是当你dispatch的时候,React只是记住了action - 它会在下一次渲染中再次调用reducer。在那个时候,新的props就可以被访问到,而且reducer调用也不是在effect里。
这就是为什么我倾向认为useReducer是Hooks的“作弊模式”。它可以把更新逻辑和描述发生了什么分开。结果是,这可以帮助我移除不必需的依赖,避免不必要的effect调用。
3. 把函数移到effects里面
function SearchResults()
const [query, setQuery] = useState('react');
useEffect(() =>
function getFetchUrl()
return 'https://hn.algolia.com/api/v1/search?query=' + query;
// 这个effect依赖的函数1
async function fetchData()
const result = await axios(getFetchUrl());
setData(result.data);
// 这个effect以来的函数2
fetchData();
, [query]); // OK
// ...
4 .实在不能放到effects里面的情况
// 只执行一次的useEffect
function SearchResults()
function getFetchUrl(query)
return 'https://hn.algolia.com/api/v1/search?query=' + query;
useEffect(() =>
const url = getFetchUrl('react');
...
, []);
// 没使用依赖,只会在初始化的时候执行一次,
useEffect(() =>
const url = getFetchUrl('redux');
...
, []);
...
// 函数作为依赖,会怎样呢?
function SearchResults()
function getFetchUrl(query)
return 'https://hn.algolia.com/api/v1/search?query=' + query;
useEffect(() =>
const url = getFetchUrl('react');
, [getFetchUrl]);
useEffect(() =>
const url = getFetchUrl('redux');
, [getFetchUrl]);
//每次渲染其实函数都是新的,所以这个依赖完全是废的,
// 其实还是每次刷新都触发effect执行,也就是请求数据
// 解决方法1 :如果一个函数没有使用组件内的任何值,
// 就把他提到组件外面定义,然后就可以自由的在effect里面使用
function getFetchUrl(query)
return 'https://hn.algolia.com/api/v1/search?query=' + query;
function SearchResults()
useEffect(() =>
const url = getFetchUrl('react');
, []);
useEffect(() =>
const url = getFetchUrl('redux');
, []);
// 此时不需要再设为依赖,因为他不在渲染范围内,
// 不会被数据流影响,不会因为props,state而改变
//解决方法2:包装为useCallck hook
function SearchResults()
const getFetchUrl = useCallback((query) =>
return 'https://hn.algolia.com/api/v1/search?query=' + query;
, []);
useEffect(() =>
const url = getFetchUrl('react');
, [getFetchUrl]);
useEffect(() =>
const url = getFetchUrl('redux');
, [getFetchUrl]);
// 本质上是给函数添加了一层依赖检查,只有函数依赖的参数发生变化,
// 函数才会变化,而不是仅仅简单的去掉函数的依赖,
// 那么effect依赖数组的检查是不是也可以这么来??
往期阅读
6、自定义 Hook
以上是关于关于hooks,你该知道的的主要内容,如果未能解决你的问题,请参考以下文章
HashMap源码分析(JDK1.8)- 你该知道的都在这里了
wwwwjs777net13094391112关于区块链,你该知道的事