回答:
既存のライフサイクルメソッド(のいずれかを使用することはできませんcomponentDidMount
、componentDidUpdate
、componentWillUnmount
フックになど)。これらはクラスコンポーネントでのみ使用できます。また、フックを使用すると、機能コンポーネントでのみ使用できます。以下の行は、React docからのものです。
あなたはクラスのライフサイクルメソッドを反応させるのに精通している場合、あなたは考えることができます
useEffect
ようフックcomponentDidMount
、componentDidUpdate
とcomponentWillUnmount
組み合わせます。
つまり、機能コンポーネントのクラスコンポーネントからこれらのライフサイクルメソッドを模倣することができます。
componentDidMount
コンポーネントがマウントされると、内部のコードが1回実行されます。useEffect
この動作に相当するフックは
useEffect(() => {
// Your code here
}, []);
ここの2番目のパラメーター(空の配列)に注意してください。これは一度だけ実行されます。
2番目のパラメーターuseEffect
がない場合、コンポーネントのすべてのレンダリングで危険な可能性があるフックが呼び出されます。
useEffect(() => {
// Your code here
});
componentWillUnmount
クリーンアップに使用します(イベントリスナーの削除、タイマーのキャンセルなど)。以下のように、イベントリスナーを追加しcomponentDidMount
て削除するとcomponentWillUnmount
します。
componentDidMount() {
window.addEventListener('mousemove', () => {})
}
componentWillUnmount() {
window.removeEventListener('mousemove', () => {})
}
上記のコードに相当するフックは次のようになります
useEffect(() => {
window.addEventListener('mousemove', () => {});
// returned function will be called on component unmount
return () => {
window.removeEventListener('mousemove', () => {})
}
}, [])
useEffect()
おかげで機能が本当によくわかりました。
componentWillMount
componentWillMount
ではなくと同等の質問がされましたcomponentWillUnmount
。この答えは確かにまったく質問に答えることはなく、OPがすでに知っていることを暗示していることを繰り返します。
ほとんどの場合useComponentDidMount
、使用するツールです。コンポーネントがマウントされた後(最初のレンダリング)に1回だけ実行されます。
const useComponentDidMount = func => useEffect(func, []);
クラスのコンポーネントcomponentWillMount
はレガシーと見なされることに注意することが重要です。コンポーネントがマウントされる前にコードを1回だけ実行する必要がある場合は、コンストラクターを使用できます。詳細はこちら。機能コンポーネントにはコンストラクタに相当するものがないため、コンポーネントのマウントの前にフックを使用してコードを1回だけ実行することは、場合によっては意味があるかもしれません。カスタムフックでそれを実現できます。
const useComponentWillMount = func => {
const willMount = useRef(true);
if (willMount.current) {
func();
}
willMount.current = false;
};
ただし、落とし穴があります。非同期で状態を設定するためにこれを使用しないでください(サーバー要求の後など。初期のレンダリングに影響を与えることが予想されるため)。このような場合はで処理する必要がありuseComponentDidMount
ます。
const Component = (props) => {
useComponentWillMount(() => console.log("Runs only once before component mounts"));
useComponentDidMount(() => console.log("Runs only once after component mounts"));
...
return (
<div>{...}</div>
);
}
componentWillMount
基づくのこの機能実装 にuseEffect
は、2つの問題があります。1つ目は、機能コンポーネントにマウントライフサイクルがないことRuns only once before component mounts
です。コンポーネントがレンダリングされた後に両方のフックが実行されるため、誤解を招きます。2つ目は、componentWillMount
サーバーレンダリングで呼び出され、呼び出されuseEffect
ないことです。UNSAFE_componentWillMount
サーバーサイドで副作用をトリガーする唯一の方法であるため、多くのライブラリが依然依存しています。
reactjs.orgによると、componentWillMountは将来サポートされなくなる予定です。 https://reactjs.org/docs/react-component.html#unsafe_componentwillmount
componentWillMountを使用する必要はありません。
コンポーネントがマウントされる前に何かを実行したい場合は、constructor()で実行してください。
ネットワーク要求を行う場合は、componentWillMountで行わないでください。これを行うと、予期しないバグが発生するためです。
ネットワーク要求は、componentDidMountで実行できます。
それが役に立てば幸い。
2019年8月3日更新
componentWillMountを要求する理由は、おそらくレンダリング前に状態を初期化したいためです。
useStateで実行してください。
const helloWorld=()=>{
const [value,setValue]=useState(0) //initialize your state here
return <p>{value}</p>
}
export default helloWorld;
または、たとえば、元のコードが次のようになっている場合は、componentWillMountで関数を実行したいとします。
componentWillMount(){
console.log('componentWillMount')
}
フックを使用すると、ライフサイクルメソッドを削除するだけで済みます。
const hookComponent=()=>{
console.log('componentWillMount')
return <p>you have transfered componeWillMount from class component into hook </p>
}
useEffectに関する最初の回答に何かを追加したいだけです。
useEffect(()=>{})
useEffectはすべてのレンダリングで実行され、componentDidUpdate、componentDidMount、およびComponentWillUnmountの組み合わせです。
useEffect(()=>{},[])
useEffectに空の配列を追加すると、コンポーネントがマウントされたときに実行されます。これは、useEffectが、渡された配列を比較するためです。したがって、空の配列である必要はありません。変更されない配列でもかまいません。たとえば、[1,2,3]または['1,2']のようになります。useEffectは、コンポーネントがマウントされている場合にのみ実行されます。
1回だけ実行するか、すべてのレンダリング後に実行するかは、ユーザーによって異なります。何をしているのかわかっている限り、配列を追加するのを忘れても危険ではありません。
フックのサンプルを作成しました。チェックアウトしてください。
https://codesandbox.io/s/kw6xj153wr
2019年8月21日に更新
上記の回答を書いてからずっと白でした。気をつけなければならないことがあると思います。使うとき
useEffect(()=>{},[])
reactが配列[]に渡した値を比較する場合、Object.is()を使用して比較します。あなたがそれにオブジェクトを渡す場合、
useEffect(()=>{},[{name:'Tom'}])
これは次とまったく同じです。
useEffect(()=>{})
Object.is()がオブジェクトを比較するとき、値自体ではなく参照を比較するため、毎回再レンダリングされます。参照が異なるため、{} === {}がfalseを返す理由と同じです。それでも参照ではなくオブジェクト自体を比較したい場合は、次のようにすることができます。
useEffect(()=>{},[JSON.stringify({name:'Tom'})])
useLayoutEffect
[]
機能が実際に類似している場合、オブザーバーの空のセット()でこれを実現できcomponentWillMount
ます-最初のコンテンツがDOMに到達する前に実行されます-実際には2つの更新がありますが、画面に描画する前に同期されます。
例えば:
function MyComponent({ ...andItsProps }) {
useLayoutEffect(()=> {
console.log('I am about to render!');
},[]);
return (<div>some content</div>);
}
上の利益useState
イニシャライザ/セッターとのまたはuseEffect
それが存在し、レンダーパスを計算することができるけれどもある実際の再レンダリングユーザが気づく、実行されていることをDOMにする前に、最初の顕著の場合とされていない、レンダリングuseEffect
。画面にペイントする前にチェック/更新を行わなければならないため、最初のレンダリングに多少の遅延があるのは当然です。ただし、実際にはユースケースによって異なります。
私は個人的に、useMemo
何か重いことをする必要があるニッチなケースでは問題ないと思います-それがあなたがそれが例外対標準であることを覚えている限りは。
これは、useRef
フックを使用して機能コンポーネントのコンストラクターをシミュレートする方法です。
function Component(props) {
const willMount = useRef(true);
if (willMount.current) {
console.log('This runs only once before rendering the component.');
willMount.current = false;
}
return (<h1>Meow world!</h1>);
}
次にライフサイクルの例を示します。
function RenderLog(props) {
console.log('Render log: ' + props.children);
return (<>{props.children}</>);
}
function Component(props) {
console.log('Body');
const [count, setCount] = useState(0);
const willMount = useRef(true);
if (willMount.current) {
console.log('First time load (it runs only once)');
setCount(2);
willMount.current = false;
} else {
console.log('Repeated load');
}
useEffect(() => {
console.log('Component did mount (it runs only once)');
return () => console.log('Component will unmount');
}, []);
useEffect(() => {
console.log('Component did update');
});
useEffect(() => {
console.log('Component will receive props');
}, [count]);
return (
<>
<h1>{count}</h1>
<RenderLog>{count}</RenderLog>
</>
);
}
[Log] Body
[Log] First time load (it runs only once)
[Log] Body
[Log] Repeated load
[Log] Render log: 2
[Log] Component did mount (it runs only once)
[Log] Component did update
[Log] Component will receive props
もちろん、クラスコンポーネントにはBody
ステップがありません。関数とクラスの概念が異なるため、1対1のシミュレーションを行うことはできません。
最初のレンダリングの前に1回関数を実行するカスタムフックを作成しました。
useBeforeFirstRender.js
import { useState, useEffect } from 'react'
export default (fun) => {
const [hasRendered, setHasRendered] = useState(false)
useEffect(() => setHasRendered(true), [hasRendered])
if (!hasRendered) {
fun()
}
}
使用法:
import React, { useEffect } from 'react'
import useBeforeFirstRender from '../hooks/useBeforeFirstRender'
export default () => {
useBeforeFirstRender(() => {
console.log('Do stuff here')
})
return (
<div>
My component
</div>
)
}
実装するための素敵な回避策はありcomponentDidMount
やcomponentWillUnmount
とはuseEffect
。
ドキュメントに基づいて、useEffect
「クリーンアップ」関数を返すことができます。この関数は、最初のuseEffect
呼び出しでは呼び出されず、後続の呼び出しでのみ呼び出されます。
したがって、useEffect
依存関係のないフックを使用すると、コンポーネントがマウントされたときにのみフックが呼び出され、コンポーネントがアンマウントされたときに「クリーンアップ」関数が呼び出されます。
useEffect(() => {
console.log('componentDidMount');
return () => {
console.log('componentWillUnmount');
};
}, []);
cleanup return関数呼び出しは、コンポーネントがマウント解除されたときにのみ呼び出されます。
お役に立てれば。
useEffect
コールあなたがのと同じ機能を取得componentWillMount
し、componentWillUnmount
きれいな方法で
useEffect
実行されている間、レンダリング後にのみ実行されますcomponentWillMount
。
componentDidMount
いませんでしたcomponentWillMount
。私は質問でそれを逃した、私の悪い。
useMemoフックをハックして、componentWillMountライフサイクルイベントを模倣できます。ただやる:
const Component = () => {
useMemo(() => {
// componentWillMount events
},[]);
useEffect(() => {
// componentWillMount events
return () => {
// componentWillUnmount events
}
}, []);
};
状態に影響を与える何かの前に、useMemoフックを保持する必要があります。これは意図された方法ではありませんが、すべてのcomponentWillMountの問題に対して私にとってはうまくいきました。
これが機能するのは、useMemoが実際に値を返す必要がなく、実際に値を使用する必要がないためです。ただし、一度だけ実行される依存関係( "[]")に基づいて値を記憶し、コンポーネントの上にコンポーネントが他より先にマウントされると1回実行されます。
https://reactjs.org/docs/hooks-reference.html#usememo
useMemoに渡された関数はレンダリング中に実行されることに注意してください。レンダリング中に通常は行わないことは何もしないでください。たとえば、副作用はuseMemoではなくuseEffectに属します。
ベン・カープの答えは私にとって唯一有効なもののようです。
しかし、関数型の方法を使用しているので、別のアプローチが閉鎖とHoCから利益を得ることができます:
const InjectWillmount = function(Node, willMountCallback) {
let isCalled = true;
return function() {
if (isCalled) {
willMountCallback();
isCalled = false;
}
return Node;
};
};
次にそれを使用します:
const YourNewComponent = InjectWillmount(<YourComponent />, () => {
console.log("your pre-mount logic here");
});
元の質問に対する簡単な回答componentWillMount
、Reactフックでどのように使用できるか:
componentWillMount
される非推奨と従来考えられて。Reactの推奨:
通常、状態の初期化には、代わりにコンストラクタ()を使用することをお勧めします。
今すぐにフックよくある質問あなたは、機能コンポーネントのクラスのコンストラクタの同等が何であるか、見つけます:
コンストラクター:関数コンポーネントはコンストラクターを必要としません。状態は、useState呼び出しで初期化できます。初期状態の計算に負荷がかかる場合は、useStateに関数を渡すことができます。
したがって、の使用例はcomponentWillMount
次のようになります。
const MyComp = () => {
const [state, setState] = useState(42) // set initial value directly in useState
const [state2, setState2] = useState(createInitVal) // call complex computation
return <div>{state},{state2}</div>
};
const createInitVal = () => { /* ... complex computation or other logic */ return 42; };