Как вызвать функцию загрузки с помощью React useEffect только один раз
Хук useEffect React будет запускать переданную функцию при каждом изменении. Это можно оптимизировать, чтобы он вызывался только при изменении желаемых свойств.
Что если я хочу вызвать функцию инициализации из componentDidMount
и не вызывать ее снова при изменениях? Допустим, я хочу загрузить объект, но функция загрузки не требует никаких данных от компонента. Как мы можем сделать это, используя хук useEffect
?
class MyComponent extends React.PureComponent {
componentDidMount() {
loadDataOnlyOnce();
}
render() { ... }
}
С крючками это может выглядеть так:
function MyComponent() {
useEffect(() => {
loadDataOnlyOnce(); // this will fire on every change :(
}, [...???]);
return (...);
}
Ответы
Ответ 1
Если вы хотите запустить только функцию, заданную для useEffect
после первоначального рендеринга, вы можете дать ей пустой массив в качестве второго аргумента.
function MyComponent() {
useEffect(() => {
loadDataOnlyOnce();
}, []);
return <div> {/* ... */} </div>;
}
Ответ 2
TL; DR
useEffect(yourCallback, [])
- вызовет обратный вызов только после первого рендера.
Детальное объяснение
useEffect
запускается по умолчанию после каждого рендеринга компонента (таким образом вызывая эффект).
Размещая useEffect
в вашем компоненте, вы сообщаете React, что хотите запустить обратный вызов в качестве эффекта. React запустит эффект после рендеринга и после обновления DOM.
Если вы передаете только обратный вызов - обратный вызов будет выполняться после каждого рендеринга.
При передаче второго аргумента (массива) React будет запускать обратный вызов после первого рендеринга и каждый раз, когда один из элементов в массиве изменяется. например, при размещении useEffect(() => console.log('hello'), [someVar, someOtherVar])
- обратный вызов будет выполняться после первого рендеринга и после любого рендеринга, что один из someVar
или someOtherVar
изменяется.
Передавая второй аргумент пустой массив, React будет сравнивать после каждого рендеринга массив и будет видеть, что ничего не изменилось, вызывая обратный вызов только после первого рендеринга.
Ответ 3
Передайте пустой массив в качестве второго аргумента useEffect
. Это фактически говорит React, цитируя документы:
Это говорит React, что ваш эффект не зависит от каких-либо значений из реквизита или состояния, поэтому его не нужно повторно запускать.
Вот фрагмент, который вы можете запустить, чтобы показать, что он работает:
function App() {
const [user, setUser] = React.useState(null);
React.useEffect(() => {
fetch('https://randomuser.me/api/')
.then(results => results.json())
.then(data => {
setUser(data.results[0]);
});
}, []); // Pass empty array to only run once on mount.
return <div>
{user ? user.name.first : 'Loading...'}
</div>;
}
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<div id="app"></div>
Ответ 4
хук useMountEffect
Запуск функции только один раз после монтирования компонентов является настолько распространенным шаблоном, что он оправдывает свою собственную ловушку, которая скрывает детали реализации.
const useMountEffect = (fun) => useEffect(fun, [])
Используйте его в любом функциональном компоненте.
function MyComponent() {
useMountEffect(function) // function will run only once after it has mounted.
return <div>...</div>;
}
О хуке useMountEffect
При использовании useEffect
со вторым аргументом массива React запускает обратный вызов после монтирования (начального рендеринга) и после изменения значений в массиве. Поскольку мы передаем пустой массив, он будет работать только после монтирования.
Ответ 5
Так что, если ваш эффект требует зависимости, и вы все еще хотите запустить его только один раз?
useEffect(() => {
dispatch({
type: 'get',
route: 'todos'
})
}, [dispatch])
Когда я Line 14: React Hook useEffect has a missing dependency: 'dispatch'. Either include it or remove the dependency array
рассылку, мой браузер сообщает мне следующее: Line 14: React Hook useEffect has a missing dependency: 'dispatch'. Either include it or remove the dependency array
Line 14: React Hook useEffect has a missing dependency: 'dispatch'. Either include it or remove the dependency array
Ответ 6
Мне нравится определять функцию mount
, она обманывает EsLint так же, как useMount
, и я нахожу ее более понятной.
const mount = () => {
console.log('mounted')
// ...
const unmount = () => {
console.log('unmounted')
// ...
}
return unmount
}
useEffect(mount, [])