关于新提出的React Effect Hook;
-
Effect
钩子(useEffect()
(的优点和用例是什么? -
为什么它更可取&它与
componentDidMount/componentDidUpdate/componentWillUnmount
(性能/可读性(有何不同?
文档指出:
函数组件的主体内不允许出现突变、订阅、定时器、日志记录和其他副作用(称为React的渲染阶段(。
但我认为在componentDidUpdate等生命周期方法中使用这些行为而不是在render方法中使用已经是常识了。
还有人提到:
传递给useEffect的函数将在渲染提交到屏幕后运行。
但这不是componentDidMount
&componentDidUpdate
怎么办?
-
Effect
挂钩(useEffect()
(的优势和用例是什么?优势
主要是,钩子通常能够提取和重用跨多个组件通用的有状态逻辑,而不需要更高阶的组件或呈现道具。
第二个好处(特别是效果挂钩(是避免了在
componentDidUpdate
中未正确处理状态相关副作用时可能出现的错误(因为效果挂钩确保在每次渲染时都设置并删除这些副作用(。另请参阅下面详细介绍的性能和可读性优势。
用例
任何使用生命周期方法实现有状态逻辑的组件——Effect钩子是一种"更好的方法"。
-
为什么它更可取&它与
componentDidMount
/componentDidUpdate
/componentWillUnmount
(性能/可读性(有何不同?为什么它更可取
因为上面和下面详述的优点。
它与生命周期方法的区别
性能
效果挂钩——
- 感觉比生命周期方法更具响应性,因为它们不会阻止浏览器更新屏幕
- 然而,将在每次渲染中设置和删除副作用,这可能会很昂贵…
- …因此可以被优化为完全跳过,除非特定状态已经被更新
;
可读性
效果挂钩导致:
-
更简单、更可维护的组件,因为它能够将以前必须在同一组生命周期方法中表达的不相关行为拆分为每个此类行为的单个挂钩——例如:
componentDidMount() { prepareBehaviourOne(); prepareBehaviourTwo(); } componentDidUnmount() { releaseBehaviourOne(); releaseBehaviourTwo(); }
变为:
useEffect(() => { prepareBehaviourOne(); return releaseBehaviourOne; }); useEffect(() => { prepareBehaviourTwo(); return releaseBehaviourTwo; });
请注意,与
BehaviourOne
相关的代码现在与与BehaviourTwo
相关的代码明显分离,而以前它混合在每个生命周期方法中 -
更少的样板文件,这是因为消除了在多个生命周期方法中重复相同代码的任何需要(例如
componentDidMount
和componentDidUpdate
之间常见的(——例如:componentDidMount() { doStuff(); } componentDidUpdate() { doStuff(); }
变为:
useEffect(doStuff); // you'll probably use an arrow function in reality
以下是ReactConf2018Dan Abramov演讲中解释差异的一个例子:
以下是以下示例的一些发现:
- 您将使用钩子编写更少的样板代码
- 使用
useEffect()
访问生命周期更新和状态更新 - 关于性能,一个方面是:
与componentDidMount和componentDidUpdate不同,传递给useEffect的函数在布局和绘制后,在延迟事件期间激发
- 代码共享太容易了,可以在同一组件内多次实现useEffect((以达到不同的目的
- 您可以通过将数组作为第二个参数传递给
useEffect()
钩子来更有效地控制组件重新渲染,当您仅在装载和卸载时将空数组[]传递给渲染组件时,这非常有效 - 使用多个
useEffect()
挂钩来分离关注点并作出反应将:
Hooks允许我们根据代码的执行情况而不是生命周期方法名称来分割代码。React将按照指定的顺序应用组件使用的每一种效果
使用类:
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
componentDidMount() {
document.title = `You clicked ${this.state.count} times`;
}
componentDidUpdate() {
document.title = `You clicked ${this.state.count} times`;
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
使用挂钩:
import { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useEffect在状态更改时运行。
import { useState, useEffect } from 'react';
function Example() {
const [Age, setAge] = useState(33);
const [Somestate,setSomestate]=useState(initilaestate);
useEffect(() => {
console.log('the age is changed to ',Age);
});
// you can use useEffect as many times you want in you component
useEffect(() => {
console.log('the age is changed to ',Age);
},[someState]);//here you tell useEffect what state to watch if you want to watch the changing of a particular state and here we care about someState
return (
<div>
<p>age increased to {Age}</p>
<button onClick={() => setAge(count + 1)}>
Increase age by One
</button>
</div>
);
}
```