pure function:单纯返回jsx元素的组件
在使用react函数组件时,理论上函数组件只会进行不改变内部状态值的计算,以及返回html代码。一个pure函数就是如此,例如一个函数组件接受一个id作为传入属性,注意这里传入的id并没有发生变化,我们只是简单进行了输出和数学计算:
// this is a pure function!
export default function person({ id }) {
return (
<>
<p>Nice to meet you! #{id}</p>
<p>Change your id to #{id*3}</p>
</>
)
}
impure function:不仅仅只是返回jsx元素
然而实际运用中,一个组件绝不止单纯返回jsx代码,在最后返回渲染代码之前可能还需要更多操作,例如修改DOM,获取数据,修改表单输入,提交表单甚至是重定向一个新页面。react doc将这些情况归纳为事件处理器(event handler)。因为组件内部的状态值被修改了,因此会发生副作用(side effects),这时候useEffect就发挥作用了。
// this is not a pure function!
export default function person({ id }) {
let cnt = 0;
return (
<>
<p>Nice to meet you! #{id}</p>
<p>Change your id to #{id*3}</p>
<p>Let's change the count number: {cnt++}</p>
</>
)
}
useEffect在执行什么:一个函数
useEffect本身就是一个函数,它的第一个参数也是函数,而且这个函数会改变组建的状态,所以我们将这个函数放入useEffect中
useEffect(() => {
if (welcome) {
document.querySelector("p").innerHTML = 'welcome, user!';
}
})
这个函数改变了p标签下的文本,也就是修改了DOM,属于副作用的范围。
注意:使用useEffect的情况应该是组件中被用于渲染的状态发生了改变,而组件中有些状态值是不参与渲染的,这个时候就不需要使用useEffect了。
useEffect的第二个参数:什么时候运行这个函数?
第二个参数就是一个包含了所有依赖项的列表,说明当这个列表中的任意对象的状态发生改变时,useEffect就会激活。
// 依赖不为空:当welcome发生改变时,输出不同的文本
useEffect(() => {
if (welcome) {
document.querySelector("p").innerHTML = 'welcome, user!';
}
else {
document.querySelector("p").innerHTML = 'Hola! como easta?';
}
}, [welcome])
依赖可以为空或没有
// 依赖为空:只在组件第一次渲染时运行,重新渲染就不会再跑一次了
useEffect(() => {
conn = getConnection()
setMessages(conn.getMessages(id))
}, [])
// 没有依赖:无上限地渲染,不建议因为不停重复渲染会导致性能下降,很多时候也没必要
useEffect(() => {
conn = getConnection()
setMessages(conn.getMessages(id))
})
useEffect运行的时机:在网页更新之后
根据react docs,useEffect会在建立网页的最后一步commit中触发,准确来说是在DOM被渲染/更新之后,然后由useEffect中的函数来更新部分有变化的DOM。
但是在某些情况下,有些状态值不会导致DOM变化,且函数也没有直接修改DOM的代码,因此即便使用useEffect也没用,数据不会被更新甚至渲染,这时候就要使用useMemo在渲染/更新之前来控制这些状态。
总结
- 大部分组件会有修改DOM和jsx元素的代码,因此不是pure function
- useEffect是针对那些有副作用的组件,并通过依赖来控制触发的条件
- useEffect运行的时候网页已经渲染完毕了,要注意其在react渲染全过程中的时间点