Есть ли способы имитировать componentDidMount в функциональных компонентах React с помощью хуков?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы хотите использовать useEffect(), который, в зависимости от того, как вы используете функцию, может действовать так же, как componentDidMount ().
Например. вы можете использовать настраиваемое свойство состояния loaded, для которого изначально установлено значение false, и переключить его на true при рендеринге и активировать эффект только при изменении этого значения.
В функциональных компонентах нет componentDidMount, но перехватчики React предоставляют способ эмуляции поведения с помощью перехватчика useEffect.
Передайте пустой массив в качестве второго аргумента useEffect(), чтобы запускать только обратный вызов только при монтировании.
Пожалуйста, прочтите документация на useEffect.
function ComponentDidMount() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
console.info('componentDidMount');
}, []);
return (
<div>
<p>componentDidMount: {count} times</p>
<button
onClick = {() => {
setCount(count + 1);
}}
>
Click Me
</button>
</div>
);
}
ReactDOM.render(
<div>
<ComponentDidMount />
</div>,
document.querySelector("#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>Для стабильной версии хуков (React Version 16.8.0+)
Для componentDidMount
useEffect(() => {
// Your code here
}, []);
Для componentDidUpdate
useEffect(() => {
// Your code here
}, [yourDependency]);
Для componentWillUnmount
useEffect(() => {
// componentWillUnmount
return () => {
// Your code here
}
}, [yourDependency]);
Итак, в этой ситуации вам нужно передать свою зависимость в этот массив. Предположим, у вас есть такое состояние
const [count, setCount] = useState(0);
И всякий раз, когда количество увеличивается, вы хотите повторно визуализировать свой функциональный компонент. Тогда ваш useEffect должен выглядеть так
useEffect(() => {
// <div>{count}</div>
}, [count]);
Таким образом, всякий раз, когда ваш счетчик обновляется, ваш компонент будет повторно визуализироваться. Надеюсь, это немного поможет.
Подробное объяснение! Есть ли способ имитировать componentDidReceiveProps?
Я не знаю об этом, даже если он существует. Вы можете проверить эту ветку на github.com/facebook/react/issues/3279
Спасибо за это, так как я не знал о втором аргументе в useState. Всем, кто читает это, имейте в виду, что оставление второго аргумента undefined приведет к срабатыванию вашего эффекта при каждом рендеринге (если я не ошибаюсь).
Вы имеете в виду зависимости useEffect (передача массива зависимостей)? Если да, то, если вы оставите поле пустым, это ошибка в коде. Для деконструкции массива вам понадобятся оба параметра [count, setCount], потому что count - это ваша переменная состояния в этом примере, а setCount - ваша функция для обновления этого состояния.
Спасибо за ответ. Документация по этому поводу здесь responsejs.org/docs/hooks-effect.html
Я пытался использовать пустой массив зависимостей для имитации componentDidMount. Проблема в том, что это обычно приводит к предупреждению: «React Hook useEffect имеет недостающую зависимость: <some prop>. Либо включите его, либо удалите массив зависимостей response-hooks / excustive-deps». Применение любого из предложенных «исправлений» заставляет его больше не вести себя как componentDidMount. Я делаю что-то неправильно?
Этот ответ неверен, поскольку предполагает, что это эквивалент componentDidMount (вопрос был задан для эквивалент), он показывает только обходной путь, который работает в некоторых случаях. В правильном ответе должно быть указано, что эквивалента нет, и показаны рекомендуемые обходные пути для всех случаев использования.
Ответ не утверждает, что он равен чему-либо, предложение заканчивается надеждой на то, что оно поможет. Так что я не вижу здесь ничего плохого. И, похоже, многим это помогло. Но я открыт для любых предложений по повышению надежности этого ответа, поскольку в этом вся цель. @kca
Это самая краткая документация по useEffect () в Интернете.
Хотя принятый ответ работает, это не рекомендуется. Если у вас более одного состояния и вы используете его с useEffect, он выдаст предупреждение о добавлении его в массив зависимостей или о том, что он не используется вообще.
Иногда это вызывает проблему, которая может дать вам непредсказуемый результат. Поэтому я предлагаю вам приложить немного усилий, чтобы переписать вашу функцию как класс. Изменений очень мало, и вы можете иметь некоторые компоненты как класс, а некоторые как функцию. Вы не обязаны использовать только одно соглашение.
Возьмем, к примеру,
function App() {
const [appointments, setAppointments] = useState([]);
const [aptId, setAptId] = useState(1);
useEffect(() => {
fetch('./data.json')
.then(response => response.json())
.then(result => {
const apts = result.map(item => {
item.aptId = aptId;
console.info(aptId);
setAptId(aptId + 1);
return item;
})
setAppointments(apts);
});
}, []);
return(...);
}
и
class App extends Component {
constructor() {
super();
this.state = {
appointments: [],
aptId: 1,
}
}
componentDidMount() {
fetch('./data.json')
.then(response => response.json())
.then(result => {
const apts = result.map(item => {
item.aptId = this.state.aptId;
this.setState({aptId: this.state.aptId + 1});
console.info(this.state.aptId);
return item;
});
this.setState({appointments: apts});
});
}
render(...);
}
Это только для примера. так что давайте не будем говорить о передовых методах работы или потенциальных проблемах с кодом. И то, и другое имеет одинаковую логику, но последнее работает только так, как ожидалось. Вы можете получить функциональность componentDidMount с запущенным useEffect в это время, но по мере роста вашего приложения есть вероятность, что вы МОЖЕТЕ столкнуться с некоторыми проблемами. Так что вместо того, чтобы переписывать на этом этапе, лучше сделать это на ранней стадии.
Кроме того, ООП не так уж и плох, если бы было достаточно процедурно-ориентированного программирования, у нас никогда не было бы объектно-ориентированного программирования. Иногда это больно, но лучше (технически не говоря уже о личных проблемах).
Я сделал это. У меня возникла проблема с использованием крючков. Проблема исчезла после преобразования его в класс.
Мне еще предстоит увидеть ошибку useEffect, которую нельзя было бы решить путем рефакторинга кода - включая этот пример. Использование версии обратного вызова setState или полное перемещение нарушающей функции из цикла рендеринга часто дает трюк - в противном случае ваше состояние, вероятно, слишком сложное и вам нужно реализовать свой собственный редуктор. Хуки не являются обязательными, но это явно будущее React. Я рекомендую прочитать этот отличный статья об использовании эффекта - он действительно помог мне сориентироваться, когда я начал сталкиваться с этими проблемами.
точный эквивалентный крючок для componentDidMount () -
useEffect(()=>{},[]);
надеюсь, что это поможет :)
Не существует точного эквивалента для componentDidMount в перехватчиках реакции.
По моему опыту, перехватчики реакции требуют другого мышления при их разработке, и, вообще говоря, вы не должны сравнивать их с методами класса, такими как componentDidMount.
С учетом сказанного, есть способы, которыми вы можете использовать хуки для получения аналогичного эффекта к componentDidMount.
Решение 1:
useEffect(() => {
console.info("I have been mounted")
}, [])
Решение 2:
const num = 5
useEffect(() => {
console.info("I will only run if my deps change: ", num)
}, [num])
Решение 3 (с функцией):
useEffect(() => {
const someFunc = () => {
console.info("Function being run after/on mount")
}
someFunc()
}, [])
Решение 4 (useCallback):
const msg = "some message"
const myFunc = useCallback(() => {
console.info(msg)
}, [msg])
useEffect(() => {
myFunc()
}, [myFunc])
Решение 5 (проявить творческий подход):
export default function useDidMountHook(callback) {
const didMount = useRef(null)
useEffect(() => {
if (callback && !didMount.current) {
didMount.current = true
callback()
}
})
}
Стоит отметить, что решение 5 действительно следует использовать только в том случае, если ни одно из других решений не работает для вашего варианта использования. Если вы все же решите, что вам нужно решение 5, я рекомендую использовать этот готовый крючок use-did-mount.
Источник (подробнее): Использование componentDidMount в перехватчиках реакции
Хук useEffect () позволяет нам достичь функциональности componentDidMount, componentDidUpdate функциональности componentWillUnMount.
Различный синтаксис useEffect () позволяет реализовать каждый из вышеперечисленных методов.
i) componentDidMount
useEffect(() => {
//code here
}, []);
ii) componentDidUpdate
useEffect(() => {
//code here
}, [x,y,z]);
//where x,y,z are state variables on whose update, this method should get triggered
iii) componentDidUnmount
useEffect(() => {
//code here
return function() {
//code to be run during unmount phase
}
}, []);
Вы можете проверить официальный сайт реакции для получения дополнительной информации. Официальная страница React на хуках
Информация об асинхронных функциях внутри хука:
Обратные вызовы эффектов синхронны, чтобы предотвратить состояние гонки. Поместите асинхронную функцию внутрь:
useEffect(() => {
async function fetchData() {
// You can await here
const response = await MyAPI.getData(someId);
// ...
}
fetchData();
}, [someId]); // Or [] if effect doesn't need props or state
import React, { 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>
);
}
Посетите этот официальные документы. Очень легко понять последний способ.
ComponentDidMount
useEffect(() => {
//code here
}, []);
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
});
Это решение не идеально. Плохая идея использовать значение состояния только для определения того, смонтирован ли компонент. Кроме того, если бы вы использовали свойство, было бы лучше использовать ref, поскольку он не запускал бы повторную визуализацию.