如何在 React 中使用带钩子的生命周期方法?
How to use lifecycle methods with hooks in React?
我已经了解了 React v16.7.0 中引入的钩子。
https://reactjs.org/docs/hooks-intro.html
所以我对钩子的理解是我们可以在功能组件中使用状态而不用在 React 中编写 class 组件。这真是一个了不起的功能。
但我不清楚在功能组件中使用钩子。
import { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
如果使用了hooks,如何在上述功能组件中使用生命周期方法?
好吧,您实际上没有生命周期方法。 =) 但您可以使用此处显示的效果挂钩 https://reactjs.org/docs/hooks-effect.html
效果挂钩将能够复制 componentDidMount、componentDidUpdate 和 componentWillUnmount 的行为
所以你真的不需要组件中的生命周期方法。效果挂钩取而代之。 =)
阅读上面的 link,您将获得一些有关它们如何工作的示例。
React 团队为此提供了一个 useEffect
钩子。让我们以您的示例中的组件为计数添加服务器上传,否则我们将把它放在例如componentDidUpdate
:
import { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
fetch(
'server/url',
{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({count}),
}
);
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
在这个例子中这似乎不是一个巨大的胜利,因为它不是。但是生命周期方法的问题是您只能在组件中获得其中的每一个。如果你想上传到服务器,触发事件,将消息放入队列,并且 none 这些东西是相关的怎么办?太糟糕了,他们都挤在 componentDidUpdate
里。或者你有 n
层包装的 HOCs 用于你想做的 n
事情。但是使用钩子,您可以将所有这些拆分为对 useEffect
的解耦调用,而无需不必要的 HOC 层。
以下是最常见生命周期的示例:
componentDidMount
将一个空数组作为第二个参数传递给 useEffect()
到 运行 仅在挂载时回调。
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
}, []); // Pass an empty array to run only callback on mount only.
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
componentDidUpdate
(宽松)
通过仅将单个参数传递给 useEffect
,它会在每次渲染后 运行。这是一个松散的等价物,因为这里略有不同,componentDidUpdate
不会在第一次渲染后 运行 而是在每次渲染后挂钩版本 运行s。
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
}); // No second argument, so run after every render.
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
componentDidUpdate
(严格)
这个例子与上面例子的区别在于这里的回调不会在初始渲染时运行,严格模拟componentDidUpdate
的语义。这个,功劳全归于他。
function Example() {
const [count, setCount] = useState(0);
const firstUpdate = useRef(true);
useLayoutEffect(() => {
if (firstUpdate.current) {
firstUpdate.current = false;
return;
}
console.log('componentDidUpdate');
});
return (
<div>
<p>componentDidUpdate: {count} times</p>
<button
onClick={() => {
setCount(count + 1);
}}
>
Click Me
</button>
</div>
);
}
componentWillUnmount
Return useEffect
的回调参数中的回调,它将在卸载前调用。
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
// Return a callback in useEffect and it will be called before unmounting.
return () => {
console.log('componentWillUnmount!');
};
}, []);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
shouldComponentUpdate
您已经可以使用 React.PureComponent
或 React.memo
在组件级别实现此目的。为了防止重新渲染子组件,此示例取自 React docs:
function Parent({ a, b }) {
// Only re-rendered if `a` changes:
const child1 = useMemo(() => <Child1 a={a} />, [a]);
// Only re-rendered if `b` changes:
const child2 = useMemo(() => <Child2 b={b} />, [b]);
return (
<>
{child1}
{child2}
</>
)
}
getDerivedStateFromProps
同样,摘自 React docs
function ScrollView({row}) {
let [isScrollingDown, setIsScrollingDown] = useState(false);
let [prevRow, setPrevRow] = useState(null);
if (row !== prevRow) {
// Row changed since last render. Update isScrollingDown.
setIsScrollingDown(prevRow !== null && row > prevRow);
setPrevRow(row);
}
return `Scrolling down: ${isScrollingDown}`;
}
getSnapshotBeforeUpdate
钩子还没有等价物。
componentDidCatch
钩子还没有等价物。
功能组件是纯粹的无状态组件。但是在 React 16.8 中,他们添加了 Hooks。钩子可以用来代替状态和生命周期方法。
是的,你可以把useEffect Hook as Like
componentDidMount
componentDidUpdate,
componentWillUnmount
shouldComponentUpdate合并。
注意 它是 componentDidMount , componentDidUpdate 的接近替代品并且,componentWillUnmount & shouldComponentUpdate
我已经了解了 React v16.7.0 中引入的钩子。
https://reactjs.org/docs/hooks-intro.html
所以我对钩子的理解是我们可以在功能组件中使用状态而不用在 React 中编写 class 组件。这真是一个了不起的功能。
但我不清楚在功能组件中使用钩子。
import { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
如果使用了hooks,如何在上述功能组件中使用生命周期方法?
好吧,您实际上没有生命周期方法。 =) 但您可以使用此处显示的效果挂钩 https://reactjs.org/docs/hooks-effect.html
效果挂钩将能够复制 componentDidMount、componentDidUpdate 和 componentWillUnmount 的行为
所以你真的不需要组件中的生命周期方法。效果挂钩取而代之。 =)
阅读上面的 link,您将获得一些有关它们如何工作的示例。
React 团队为此提供了一个 useEffect
钩子。让我们以您的示例中的组件为计数添加服务器上传,否则我们将把它放在例如componentDidUpdate
:
import { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
fetch(
'server/url',
{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({count}),
}
);
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
在这个例子中这似乎不是一个巨大的胜利,因为它不是。但是生命周期方法的问题是您只能在组件中获得其中的每一个。如果你想上传到服务器,触发事件,将消息放入队列,并且 none 这些东西是相关的怎么办?太糟糕了,他们都挤在 componentDidUpdate
里。或者你有 n
层包装的 HOCs 用于你想做的 n
事情。但是使用钩子,您可以将所有这些拆分为对 useEffect
的解耦调用,而无需不必要的 HOC 层。
以下是最常见生命周期的示例:
componentDidMount
将一个空数组作为第二个参数传递给 useEffect()
到 运行 仅在挂载时回调。
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
}, []); // Pass an empty array to run only callback on mount only.
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
componentDidUpdate
(宽松)
通过仅将单个参数传递给 useEffect
,它会在每次渲染后 运行。这是一个松散的等价物,因为这里略有不同,componentDidUpdate
不会在第一次渲染后 运行 而是在每次渲染后挂钩版本 运行s。
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
}); // No second argument, so run after every render.
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
componentDidUpdate
(严格)
这个例子与上面例子的区别在于这里的回调不会在初始渲染时运行,严格模拟componentDidUpdate
的语义。这个
function Example() {
const [count, setCount] = useState(0);
const firstUpdate = useRef(true);
useLayoutEffect(() => {
if (firstUpdate.current) {
firstUpdate.current = false;
return;
}
console.log('componentDidUpdate');
});
return (
<div>
<p>componentDidUpdate: {count} times</p>
<button
onClick={() => {
setCount(count + 1);
}}
>
Click Me
</button>
</div>
);
}
componentWillUnmount
Return useEffect
的回调参数中的回调,它将在卸载前调用。
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
// Return a callback in useEffect and it will be called before unmounting.
return () => {
console.log('componentWillUnmount!');
};
}, []);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
shouldComponentUpdate
您已经可以使用 React.PureComponent
或 React.memo
在组件级别实现此目的。为了防止重新渲染子组件,此示例取自 React docs:
function Parent({ a, b }) {
// Only re-rendered if `a` changes:
const child1 = useMemo(() => <Child1 a={a} />, [a]);
// Only re-rendered if `b` changes:
const child2 = useMemo(() => <Child2 b={b} />, [b]);
return (
<>
{child1}
{child2}
</>
)
}
getDerivedStateFromProps
同样,摘自 React docs
function ScrollView({row}) {
let [isScrollingDown, setIsScrollingDown] = useState(false);
let [prevRow, setPrevRow] = useState(null);
if (row !== prevRow) {
// Row changed since last render. Update isScrollingDown.
setIsScrollingDown(prevRow !== null && row > prevRow);
setPrevRow(row);
}
return `Scrolling down: ${isScrollingDown}`;
}
getSnapshotBeforeUpdate
钩子还没有等价物。
componentDidCatch
钩子还没有等价物。
功能组件是纯粹的无状态组件。但是在 React 16.8 中,他们添加了 Hooks。钩子可以用来代替状态和生命周期方法。
是的,你可以把useEffect Hook as Like
componentDidMount
componentDidUpdate,
componentWillUnmount
shouldComponentUpdate合并。
注意 它是 componentDidMount , componentDidUpdate 的接近替代品并且,componentWillUnmount & shouldComponentUpdate