web-dev-qa-db-ja.com

Reactのフックでコンポーネントを強制的に再レン​​ダリングするにはどうすればよいですか?

以下のフックの例を考慮する

   import { useState } from 'react';

   function Example() {
       const [count, setCount] = useState(0);

       return (
           <div>
               <p>You clicked {count} times</p>
               <button onClick={() => setCount(count + 1)}>
                  Click me
               </button>
          </div>
        );
     }

基本的にthis.forceUpdate()メソッドを使用して、以下の例のようにReactクラスコンポーネントでコンポーネントをすぐに再レンダリングします。

    class Test extends Component{
        constructor(props){
             super(props);
             this.state = {
                 count:0,
                 count2: 100
             }
             this.setCount = this.setCount.bind(this);//how can I do this with hooks in functional component 
        }
        setCount(){
              let count = this.state.count;
                   count = count+1;
              let count2 = this.state.count2;
                   count2 = count2+1;
              this.setState({count});
              this.forceUpdate();
              //before below setState the component will re-render immediately when this.forceUpdate() is called
              this.setState({count2: count
        }

        render(){
              return (<div>
                   <span>Count: {this.state.count}></span>. 
                   <button onClick={this.setCount}></button>
                 </div>
        }
 }

しかし、私のクエリは、上記の機能コンポーネントをフックですぐに再レンダリングさせるにはどうすればよいですか?

24
Hemadri Dasari

useStateは内部でuseReducerを使用するため、これはuseStateまたはuseReducerで可能です。

const [, updateState] = React.useState();
const forceUpdate = useCallback(() => updateState({}), []);

forceUpdateは、通常の状況下での使用を意図したものではなく、テストまたはその他の未解決のケースでのみ使用されます。この状況は、より一般的な方法で対処できます。

setCountは、不適切に使用されたforceUpdateの例です。 setStateはパフォーマンス上の理由で非同期であり、状態の更新が正しく実行されなかったからといって強制的に同期されるべきではありません。状態が以前に設定された状態に依存している場合、これは pdater function で行う必要があります。

前の状態に基づいて状態を設定する必要がある場合は、以下のupdater引数についてお読みください。

<...>

アップデーター関数によって受信された状態と小道具の両方が最新であることが保証されます。アップデータの出力は、状態と浅くマージされます。

setCountは、目的が明確ではないため、実例ではないかもしれませんが、これはアップデーター関数の場合です:

setCount(){
  this.setState(({count}) => ({ count: count + 1 }));
  this.setState(({count2}) => ({ count2: count + 1 }));
  this.setState(({count}) => ({ count2: count + 1 }));
}
13
Estus Flask

コンポーネントは状態とプロップのみに依存し、期待どおりに機能することが望ましいですが、コンポーネントを強制的に再レン​​ダリングする関数が本当に必要な場合は、useStateフックを使用して関数を呼び出すことができます必要です。

const { useState, useEffect } = React;

function Foo() {
  const [, forceUpdate] = useState();

  useEffect(() => {
    setTimeout(forceUpdate, 2000);
  }, []);

  return <div>{Date.now()}</div>;
}

ReactDOM.render(<Foo />, document.getElementById("root"));
<script src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>

<div id="root"></div>
6
Tholle

他の人が述べたように、useStateは動作します-ここに mobx-react-lite が実装されています-あなたは同様のことができます。

新しいフックuseForceUpdateを定義します-

import { useState, useCallback } from 'react'

export function useForceUpdate() {
  const [, setTick] = useState(0);
  const update = useCallback(() => {
    setTick(tick => tick + 1);
  }, [])
  return update;
}

コンポーネントで使用します-

const forceUpdate = useForceUpdate();
if (...) {
  forceUpdate(); // force re-render
}

https://github.com/mobxjs/mobx-react-lite/blob/master/src/utils.ts および https://github.com/mobxjs/mobx-を参照react-lite/blob/master/src/useObserver.ts

6
Brian Burns

次のようにuseStateを簡単に定義できます。

const [, forceUpdate] = React.useState(0);

そして使用法:forceUpdate(n => !n)

この助けを願っています!

4
Minh Kha

JSXコードでReactはブール値を出力しないという事実を利用して、通常のフックを(ab)使用して強制的に再レン​​ダリングできます。

// create a hook
const [forceRerender, setForceRerender] = React.useState(true);

// ...put this line where you want to force a rerender
setForceRerender(!forceRerender);

// ...make sure that {forceRerender} is "visible" in your js code
// ({forceRerender} will not actually be visible since booleans are
// not printed, but updating its value will nonetheless force a
// rerender)
return (
  <div>{forceRerender}</div>
)

3
Fergie

潜在的なオプションは、keyを使用して特定のコンポーネントでのみ更新を強制することです。キーを更新すると、コンポーネントのレンダリングがトリガーされます(以前は更新に失敗しました)

例えば:

const [tableKey, setTableKey] = useState(1);
...

useEffect(() => {
    ...
    setTableKey(tableKey + 1);
}, [tableData]);

...
<DataTable
    key={tableKey}
    data={tableData}/>
0
Idan