Есть ли способы имитировать componentDidMount
в функциональных компонентах React с помощью хуков?
componentDidMount для функции React / компонента хуков?
Ответы (8)
Для стабильной версии хуков (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]);
Таким образом, всякий раз, когда ваш счетчик обновляется, ваш компонент будет повторно визуализироваться. Надеюсь, это немного поможет.
useState
. Всем, кто читает это, имейте в виду, что оставление второго аргумента undefined
вызовет срабатывание вашего эффекта при каждом рендеринге (если я не ошибаюсь).
- person dimiguel; 13.03.2019
Не существует точного эквивалента для componentDidMount
в перехватчиках реакции.
По моему опыту, перехватчики реакции требуют другого мышления при их разработке, и, вообще говоря, вы не должны сравнивать их с методами класса, такими как componentDidMount
.
С учетом сказанного, есть способы, которыми вы можете использовать хуки для получения эффекта, аналогичного componentDidMount
.
Решение 1.
useEffect(() => {
console.log("I have been mounted")
}, [])
Решение 2:
const num = 5
useEffect(() => {
console.log("I will only run if my deps change: ", num)
}, [num])
Решение 3 (с функцией):
useEffect(() => {
const someFunc = () => {
console.log("Function being run after/on mount")
}
someFunc()
}, [])
Решение 4 (useCallback):
const msg = "some message"
const myFunc = useCallback(() => {
console.log(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- смонтировать.
Источник (с более подробной информацией): Использование componentDidMount в перехватчиках реакции
Функциональных компонентов componentDidMount
нет, но перехватчики React предоставляют способ эмуляции поведения с помощью перехватчика useEffect
.
Передайте пустой массив в качестве второго аргумента useEffect()
, чтобы запускать только обратный вызов только при монтировании.
Прочтите документацию на useEffect
.
function ComponentDidMount() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
console.log('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>
Хотя принятый ответ работает, это не рекомендуется. Если у вас более одного состояния и вы используете его с 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.log(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.log(this.state.aptId);
return item;
});
this.setState({appointments: apts});
});
}
render(...);
}
Это только для примера. так что давайте не будем говорить о передовых методах работы или потенциальных проблемах с кодом. Оба варианта имеют одинаковую логику, но последний работает только так, как ожидалось. Вы можете получить функциональность componentDidMount с запущенным useEffect в это время, но по мере роста вашего приложения есть вероятность, что вы МОЖЕТЕ столкнуться с некоторыми проблемами. Так что вместо того, чтобы переписывать на этом этапе, лучше сделать это на ранней стадии.
Кроме того, ООП не так уж и плох, если бы было достаточно процедурно-ориентированного программирования, у нас никогда не было бы объектно-ориентированного программирования. Иногда это больно, но лучше (технически не говоря уже о личных проблемах).
setState
или полное перемещение вызывающей нарушение функции из цикла рендеринга часто дает трюк - в противном случае ваше состояние, вероятно, слишком сложное и вам нужно реализовать свой собственный редуктор. Хуки не являются обязательными, но это явно будущее React. Я рекомендую прочитать эту отличную статью об useEffect - она действительно помогла мне обойдите его, когда я начал сталкиваться с этими проблемами.
- person lawrence-witt; 20.02.2021
точный эквивалентный крючок для componentDidMount () -
useEffect(()=>{},[]);
надеюсь, что это поможет :)
Хук 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
Вы хотите использовать useEffect()
, который, в зависимости от того, как вы используете функцию, может действовать так же, как componentDidMount ().
Например. вы можете использовать настраиваемое свойство состояния loaded
, для которого изначально установлено значение false, и переключить его на true при рендеринге и активировать эффект только при изменении этого значения.