React HooksでcomponentWillMount()を使用する方法は?


176

Reactの公式ドキュメントではそれが言及しています-

Reactクラスのライフサイクルメソッドに精通している場合は、useEffectフックを、componentDidMount、componentDidUpdate、およびcomponentWillUnmountを組み合わせたものと考えることができます。

私の質問は- componentWillMount()ライフサイクルメソッドをフックで使用するにはどうすればよいですか?

回答:


339

既存のライフサイクルメソッド(のいずれかを使用することはできませんcomponentDidMountcomponentDidUpdatecomponentWillUnmountフックになど)。これらはクラスコンポーネントでのみ使用できます。また、フックを使用すると、機能コンポーネントでのみ使用できます。以下の行は、React docからのものです。

あなたはクラスのライフサイクルメソッドを反応させるのに精通している場合、あなたは考えることができますuseEffectようフックcomponentDidMountcomponentDidUpdatecomponentWillUnmount組み合わせます。

つまり、機能コンポーネントのクラスコンポーネントからこれらのライフサイクルメソッドを模倣することができます。

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', () => {})
  }
}, [])

184
他のライフサイクルイベントについての素晴らしい説明ですが、これは特にcomponentWillMount()の代替についての質問ではありません。
シラーズ

3
私が見たPanResponderの例では、componentWillMountが必要であるように見えます。そうでない場合、未定義のpanHandlerを取得します。
Dror Bar

2
useEffect()おかげで機能が本当によくわかりました。
Iharob Al

67
なぜこれは受け入れられた答えですか?componentWillMount
Mykyboの

3
@techexpert componentWillMountではなくと同等の質問がされましたcomponentWillUnmount。この答えは確かにまったく質問に答えることはなく、OPがすでに知っていることを暗示していることを繰り返します。
JoshuaCWebDeveloper

62

useComponentDidMountフック

ほとんどの場合useComponentDidMount、使用するツールです。コンポーネントがマウントされた後(最初のレンダリング)に1回だけ実行されます。

 const useComponentDidMount = func => useEffect(func, []);

useComponentWillMount

クラスのコンポーネント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>
  );
}

完全なデモ


18
これが、質問に答えて意味のある唯一の答えです。ありがとうございました!
チュマコフ

3
これに関する唯一の問題は、状態の更新が関係しているため、余分なレンダリングが発生することです。代わりにrefを使用することにより、追加のレンダリングなしで目的の動作が得られます。 `const useComponentWillMount = func => {const willMount = useRef(true); useEffect(()=> {willMount.current = false;}、[]); if(willMount.current){func(); }}; `
remix23

2
componentWillMount基づくのこの機能実装 にuseEffectは、2つの問題があります。1つ目は、機能コンポーネントにマウントライフサイクルがないことRuns only once before component mountsです。コンポーネントがレンダリングされた後に両方のフックが実行されるため、誤解を招きます。2つ目は、componentWillMountサーバーレンダリングで呼び出され、呼び出されuseEffectないことです。UNSAFE_componentWillMountサーバーサイドで副作用をトリガーする唯一の方法であるため、多くのライブラリが依然依存しています。
Paolo Moretti

2
@PaoloMoretti、ありがとう。このcomponentWillMountフックは、クラスコンポーネントのcomponentWillMountライフサイクルとまったく同じではありません。ただし、渡された関数はすぐに実行され、最初に呼び出されたときにのみ実行されます。これは、実際には、レンダリングされる前、および初めて値を返す前に実行されることを意味します。それについて同意できますか?この名前はクラスライフサイクルバージョンから特定の意味を持つため、componentWillMountという名前の使用は理想的ではないことに同意します。おそらく「useRunPreMount」と呼ぶ方がいいでしょう。
ベン・カープ

1
@PaoloMoretti、私はそれをまったく理解していません。私はSSRを使用していませんが、私の理解では、SSRでcomponentWillMountが2回実行されます。1回はサーバーで、もう1回はクライアントで実行されます。useComponentDidMountに渡されるコールバックについても同じことが言えると思います。useComponentDidMountは、useEffectを中継してコールバックの呼び出しを停止します。useEffectのコールバックが実行されるまで、コンポーネントの関数は2回実行されます。1回はサーバーで、もう1回はクライアントで実行されます。そうではありませんか?
ベン・カープ

53

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'})])

17
そして問題は、フックでそれを実装する方法
でした

3
ただし、サポートされないため、フックを使用して実装する必要はありません。フックでそれを行う方法を学ぶ必要はありません。
MING WU 2018年

1
今、あなたはcomponentDidMountが使用する正しいライフサイクルであることを言及していることを、あなたはあなたの答えに、その後、あなたの答えは受け入れ答えよりも理にかなっていることを実装する方法を追加している可能性が
Shubhamカトリ

8
確かにこれは受け入れられる答えになるはずです。これは、ComponentWillMountがフックパラダイムで利用できないことを説明しています。機能コンポーネントの初期化が簡素化されました-それは機能の一部である必要があるだけです
Shiraz

1
これはどのようにcomponentWillMountと同じですか?コードを機能コンポーネントにスローすると、コンポーネントがマウントされるときだけでなく、すべてのレンダリングが実行されます。
オーバーコード

13

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何か重いことをする必要があるニッチなケースでは問題ないと思います-それがあなたがそれが例外対標準であることを覚えている限りは。


3
useLayoutEffectを使用する方法です!!!! これは、ユーザーがログインしているかどうかの確認に関する私の質問への回答です。(問題は、コンポーネントが読み込まれ、ユーザーがログインしているかどうかを確認することでした。)私の質問は、これは標準的な方法ですか?私はあまり多くの場所で会っていません
ジェシカ

1
ええ、それはかなり一般的です。公式のReactドキュメントでも言及されています-ユーザーが気付く前にロジックを実行するために、二重DOMレンダリングの影響により、小さなテキストでのみ。
rob2d

実際には、コンポーネントのレンダリング後に実行されます。したがって、componentWillMountとはまったく異なります。
Jiri Mihal

7

これは、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のシミュレーションを行うことはできません。


私はあなたの例に飛び込みませんでしたが、あなたの最初のコードスニペットは私のために機能します、ありがとう!
サンドリ

6

最初のレンダリングの前に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>
  )
}

3

実装するための素敵な回避策はありcomponentDidMountcomponentWillUnmountとはuseEffect

ドキュメントに基づいて、useEffect「クリーンアップ」関数を返すことができます。この関数は、最初のuseEffect呼び出しでは呼び出されず、後続の呼び出しでのみ呼び出されます。

したがって、useEffect依存関係のないフックを使用すると、コンポーネントがマウントされたときにのみフックが呼び出され、コンポーネントがアンマウントされたときに「クリーンアップ」関数が呼び出されます。

useEffect(() => {
    console.log('componentDidMount');

    return () => {
        console.log('componentWillUnmount');
    };
}, []);

cleanup return関数呼び出しは、コンポーネントがマウント解除されたときにのみ呼び出されます。

お役に立てれば。


2
componentWillMountと関係がない場合、これはどのように役立ちますか?何か不足していますか?
ZenVentzi

はい、あなたは同じであるという事実不足しているuseEffectコールあなたがのと同じ機能を取得componentWillMountし、componentWillUnmountきれいな方法で
AfikDeri

これは当てはまりません。コンポーネントがレンダリングされる前にuseEffect実行されている間、レンダリング後にのみ実行されますcomponentWillMount
オーバーコード

@Overcode私は話してcomponentDidMountいませんでしたcomponentWillMount。私は質問でそれを逃した、私の悪い。
AfikDeri

1

useMemoフックをハックして、componentWillMountライフサイクルイベントを模倣できます。ただやる:

const Component = () => {
   useMemo(() => {
     // componentWillMount events
   },[]);
   useEffect(() => {
     // componentWillMount events
     return () => {
       // componentWillUnmount events
     }
   }, []);
};

状態に影響を与える何かの前に、useMemoフックを保持する必要があります。これは意図された方法ではありませんが、すべてのcomponentWillMountの問題に対して私にとってはうまくいきました。

これが機能するのは、useMemoが実際に値を返す必要がなく、実際に値を使用する必要がないためです。ただし、一度だけ実行される依存関係( "[]")に基づいて値を記憶し、コンポーネントの上にコンポーネントが他より先にマウントされると1回実行されます。


0

https://reactjs.org/docs/hooks-reference.html#usememo

useMemoに渡された関数はレンダリング中に実行されることに注意してください。レンダリング中に通常は行わないことは何もしないでください。たとえば、副作用はuseMemoではなくuseEffectに属します。


usememoはパフォーマンスを最適化するためのものです。プロップが変更された場合、フックは既にマウントされた後で再度レンダリングされ、これにより作成者の目的が損なわれます。
max54、19年

0

ベン・カープの答えは私にとって唯一有効なもののようです。

しかし、関数型の方法を使用しているので、別のアプローチが閉鎖と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");
});

0

元の質問に対する簡単な回答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; };

0

空の依存配列をuseEffectに追加するだけで動作しcomponentDidMountます。

useEffect(() => {
  // Your code here
  console.log("componentDidMount")
}, []);

0

シミュレートするための簡単なトリックがありますcomponentDidMountし、componentWillUnmount使用してはuseEffect

useEffect(() => {
  console.log("componentDidMount");

  return () => {
    console.log("componentWillUnmount");
  };
}, []);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.