Menurut dokumen:
componentDidUpdate()
dipanggil segera setelah pembaruan terjadi. Metode ini tidak dipanggil untuk render awal.
Kita bisa menggunakan useEffect()
hook baru untuk mensimulasikan componentDidUpdate()
, tetapi sepertinya useEffect()
dijalankan setelah setiap render, bahkan untuk pertama kalinya. Bagaimana cara membuatnya tidak berjalan pada render awal?
Seperti yang Anda lihat pada contoh di bawah ini, componentDidUpdateFunction
dicetak selama render awal tetapi componentDidUpdateClass
tidak dicetak selama render awal.
function ComponentDidUpdateFunction() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
console.log("componentDidUpdateFunction");
});
return (
<div>
<p>componentDidUpdateFunction: {count} times</p>
<button
onClick={() => {
setCount(count + 1);
}}
>
Click Me
</button>
</div>
);
}
class ComponentDidUpdateClass extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
componentDidUpdate() {
console.log("componentDidUpdateClass");
}
render() {
return (
<div>
<p>componentDidUpdateClass: {this.state.count} times</p>
<button
onClick={() => {
this.setState({ count: this.state.count + 1 });
}}
>
Click Me
</button>
</div>
);
}
}
ReactDOM.render(
<div>
<ComponentDidUpdateFunction />
<ComponentDidUpdateClass />
</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>
javascript
reactjs
react-hooks
Yangshun Tay
sumber
sumber
count
?Jawaban:
Kita bisa menggunakan
useRef
hook untuk menyimpan nilai yang bisa berubah yang kita suka , jadi kita bisa menggunakannya untuk melacak apakah ini pertama kalinyauseEffect
fungsi dijalankan.Jika kita ingin efeknya berjalan dalam fase yang
componentDidUpdate
sama, kita bisa menggunakannyauseLayoutEffect
.Contoh
const { useState, useRef, useLayoutEffect } = React; function ComponentDidUpdateFunction() { const [count, setCount] = useState(0); const firstUpdate = useRef(true); useLayoutEffect(() => { if (firstUpdate.current) { firstUpdate.current = false; return; } console.log("componentDidUpdateFunction"); }); return ( <div> <p>componentDidUpdateFunction: {count} times</p> <button onClick={() => { setCount(count + 1); }} > Click Me </button> </div> ); } ReactDOM.render( <ComponentDidUpdateFunction />, 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>
sumber
useRef
denganuseState
, tetapi menggunakan setter memicu render ulang, yang tidak terjadi saat menugaskanfirstUpdate.current
jadi saya kira ini adalah satu-satunya cara yang bagus :)componentDidUpdate
dengan kait, jadi itulah mengapa saya menggunakannya.Anda dapat mengubahnya menjadi pengait khusus , seperti:
import React, { useEffect, useRef } from 'react'; const useDidMountEffect = (func, deps) => { const didMount = useRef(false); useEffect(() => { if (didMount.current) func(); else didMount.current = true; }, deps); } export default useDidMountEffect;
Contoh penggunaan:
import React, { useState, useEffect } from 'react'; import useDidMountEffect from '../path/to/useDidMountEffect'; const MyComponent = (props) => { const [state, setState] = useState({ key: false }); useEffect(() => { // you know what is this, don't you? }, []); useDidMountEffect(() => { // react please run me if 'key' changes, but not on initial render }, [state.key]); return ( <div> ... </div> ); } // ...
sumber
Saya membuat
useFirstRender
pengait sederhana untuk menangani kasus seperti memfokuskan input formulir:import { useRef, useEffect } from 'react'; export function useFirstRender() { const firstRender = useRef(true); useEffect(() => { firstRender.current = false; }, []); return firstRender.current; }
Ini dimulai sebagai
true
, kemudian beralih kefalse
dalamuseEffect
, yang hanya berjalan sekali, dan tidak pernah lagi.Di komponen Anda, gunakan:
const firstRender = useFirstRender(); const phoneNumberRef = useRef(null); useEffect(() => { if (firstRender || errors.phoneNumber) { phoneNumberRef.current.focus(); } }, [firstRender, errors.phoneNumber]);
Untuk kasus Anda, Anda hanya akan menggunakan
if (!firstRender) { ...
.sumber
@ravi, milik Anda tidak memanggil fungsi pelepasan yang diteruskan. Ini versi yang sedikit lebih lengkap:
/** * Identical to React.useEffect, except that it never runs on mount. This is * the equivalent of the componentDidUpdate lifecycle function. * * @param {function:function} effect - A useEffect effect. * @param {array} [dependencies] - useEffect dependency list. */ export const useEffectExceptOnMount = (effect, dependencies) => { const mounted = React.useRef(false); React.useEffect(() => { if (mounted.current) { const unmount = effect(); return () => unmount && unmount(); } else { mounted.current = true; } }, dependencies); // Reset on unmount for the next mount. React.useEffect(() => { return () => mounted.current = false; }, []); };
sumber
useEffect(() => {...});
dependencies
parameter saat Anda memanggilnya.@MehdiDehghani, solusi Anda berfungsi dengan baik, satu tambahan yang harus Anda lakukan adalah di unmount, setel ulang
didMount.current
nilainya kefalse
. Saat mencoba menggunakan hook khusus ini di tempat lain, Anda tidak mendapatkan nilai cache.import React, { useEffect, useRef } from 'react'; const useDidMountEffect = (func, deps) => { const didMount = useRef(false); useEffect(() => { let unmount; if (didMount.current) unmount = func(); else didMount.current = true; return () => { didMount.current = false; unmount && unmount(); } }, deps); } export default useDidMountEffect;
sumber
false
.