Reactを使用したブラウザーのサイズ変更でのレンダリングビュー


313

ブラウザウィンドウのサイズが変更されたときにReactでビューを再レンダリングするにはどうすればよいですか?

バックグラウンド

ページ上に個別にレイアウトしたいブロックがいくつかありますが、ブラウザーウィンドウが変更されたときにそれらも更新したいです。最終的な結果は、Ben Hollandの Pinterestレイアウトようなものになりますが、jQueryだけでなくReactを使用して書かれます。私はまだ道を外れています。

コード

これが私のアプリです:

var MyApp = React.createClass({
  //does the http get from the server
  loadBlocksFromServer: function() {
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      mimeType: 'textPlain',
      success: function(data) {
        this.setState({data: data.events});
      }.bind(this)
    });
  },
  getInitialState: function() {
    return {data: []};
  },
  componentWillMount: function() {
    this.loadBlocksFromServer();

  },    
  render: function() {
    return (
        <div>
      <Blocks data={this.state.data}/>
      </div>
    );
  }
});

React.renderComponent(
  <MyApp url="url_here"/>,
  document.getElementById('view')
)

次に、Blockコンポーネントがあります(Pin上のPinterestの例のa に相当)。

var Block = React.createClass({
  render: function() {
    return (
        <div class="dp-block" style={{left: this.props.top, top: this.props.left}}>
        <h2>{this.props.title}</h2>
        <p>{this.props.children}</p>
        </div>
    );
  }
});

とのリスト/コレクションBlocks

var Blocks = React.createClass({

  render: function() {

    //I've temporarily got code that assigns a random position
    //See inside the function below...

    var blockNodes = this.props.data.map(function (block) {   
      //temporary random position
      var topOffset = Math.random() * $(window).width() + 'px'; 
      var leftOffset = Math.random() * $(window).height() + 'px'; 
      return <Block order={block.id} title={block.summary} left={leftOffset} top={topOffset}>{block.description}</Block>;
    });

    return (
        <div>{blockNodes}</div>
    );
  }
});

質問

jQueryのウィンドウサイズ変更を追加する必要がありますか?もしそうなら、どこ?

$( window ).resize(function() {
  // re-render the component
});

これを行うためのより「反応する」方法はありますか?

回答:


531

Reactフックの使用:

resize次のように、ウィンドウイベントをリッスンするカスタムフックを定義できます。

import React, { useLayoutEffect, useState } from 'react';

function useWindowSize() {
  const [size, setSize] = useState([0, 0]);
  useLayoutEffect(() => {
    function updateSize() {
      setSize([window.innerWidth, window.innerHeight]);
    }
    window.addEventListener('resize', updateSize);
    updateSize();
    return () => window.removeEventListener('resize', updateSize);
  }, []);
  return size;
}

function ShowWindowDimensions(props) {
  const [width, height] = useWindowSize();
  return <span>Window size: {width} x {height}</span>;
}

ここでの利点は、ロジックがカプセル化され、ウィンドウサイズを使用したい場所ならどこでもこのフックを使用できることです。

Reactクラスの使用:

あなたはcomponentDidMountで聞くことができます、これはウィンドウの寸法を表示するだけのこのコンポーネントのようなものです(のような<span>Window size: 1024 x 768</span>):

import React from 'react';

class ShowWindowDimensions extends React.Component {
  state = { width: 0, height: 0 };
  render() {
    return <span>Window size: {this.state.width} x {this.state.height}</span>;
  }
  updateDimensions = () => {
    this.setState({ width: window.innerWidth, height: window.innerHeight });
  };
  componentDidMount() {
    window.addEventListener('resize', this.updateDimensions);
  }
  componentWillUnmount() {
    window.removeEventListener('resize', this.updateDimensions);
  }
}

5
これはどのように作動しますか?にthis.updateDimensions渡されるのaddEventListenerthis、呼び出されたときに値を持たない単なる関数参照です。匿名関数、または.bind()呼び出しを使用してaddを追加するthis必要がありますか、それとも誤解していますか?
fadedbee '20

24
@chrisdew少し遅れましたがthis、コンポーネントで直接定義されたメソッドに対してReactが自動バインドします。
ミシェルティリー2014年

3
@MattDellはい、ES6クラスは単なる通常のクラスなので、それらとの自動バインディングはありません。
ミシェルティリー

30
ノーjQueryが必要-使用innerHeightしてinnerWidthからwindow。そして、あなたはスキップすることができcomponentWillMount、あなたが使用している場合getInitialStateに設定するheightwidth
sighrobot 2016年

2
@MattDellは::、今のところバインド構文が無効になっているようです。 、バインド演算子はES8の提案です」
ジャロッドスミス

130

@SophieAlpertは正しいです、+ 1、私はこの回答に基づいて、jQueryなしで彼女のソリューションの修正バージョンを提供したいだけです。

var WindowDimensions = React.createClass({
    render: function() {
        return <span>{this.state.width} x {this.state.height}</span>;
    },
    updateDimensions: function() {

    var w = window,
        d = document,
        documentElement = d.documentElement,
        body = d.getElementsByTagName('body')[0],
        width = w.innerWidth || documentElement.clientWidth || body.clientWidth,
        height = w.innerHeight|| documentElement.clientHeight|| body.clientHeight;

        this.setState({width: width, height: height});
        // if you are using ES2015 I'm pretty sure you can do this: this.setState({width, height});
    },
    componentWillMount: function() {
        this.updateDimensions();
    },
    componentDidMount: function() {
        window.addEventListener("resize", this.updateDimensions);
    },
    componentWillUnmount: function() {
        window.removeEventListener("resize", this.updateDimensions);
    }
});

IE関連のポリフィルがバニラJSイベントリスナーに設定されている場合にのみ機能します
nnnn

@nnnn詳しく説明できますか?私はこれをChromeでのみテストしたことを認めます。window.addEventListenerは、ポリフィルなしのIEでは機能しないと言っていますか?
アンドレ・ペーニャ

2
@andrerpena caniuse.com/#search=addeventlistenerはie8に問題があることを示しています
nnnn

2
@nnnn。そうですか。はい。私のソリューションはIE 8では機能しませんが、9以降では機能します:)。ありがとう。
アンドレ・ペーニャ

35
まだ誰もが本当にIE8を気にしていますか?それともただの習慣ですか?
凍るような驚異的な

48

非常にシンプルなソリューション:

resize = () => this.forceUpdate()

componentDidMount() {
  window.addEventListener('resize', this.resize)
}

componentWillUnmount() {
  window.removeEventListener('resize', this.resize)
}

12
強制更新を抑制することを忘れないでください。そうしないと、非常にグリッチに見えます。
k2snowman69

4
また、リスナーを削除することを忘れないでくださいcomponentWillUnmount()
Jemar Jones

これが絞られている場合、これが最良のソリューションです。つまり、forceUpdate条件付きで適用される場合
asmmahmud

1
スロットルする必要があるのはforceUpdate(呼び出されるもの)ではなく、スロットルする必要があるのはサイズ変更イベントの発火(発火するもの)です。ウィンドウのサイズを大から小に変更すると、技術的にはすべてのピクセルでサイズ変更イベントを呼び出すことができます。ユーザーがこれをすばやく行うと、それはあなたが気にする以上のイベントです。さらに悪いことに、UIスレッドをJavascriptスレッドにバインドしています。つまり、アプリが各イベントを個別に処理しようとするときに、アプリが非常に遅く感じ始めることになります。
k2snowman69

1
すべてのピクセルでサイズ変更関数を実行する代わりに、一定の短い時間間隔で実行して、常に最初と最後のイベントを処理する流動性の錯覚を与え、サイズ変更を流動的に処理しているように感じさせます。
k2snowman69

42

これは、jQueryなしでes6を使用する簡単で短い例です。

import React, { Component } from 'react';

export default class CreateContact extends Component {
  state = {
    windowHeight: undefined,
    windowWidth: undefined
  }

  handleResize = () => this.setState({
    windowHeight: window.innerHeight,
    windowWidth: window.innerWidth
  });

  componentDidMount() {
    this.handleResize();
    window.addEventListener('resize', this.handleResize)
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.handleResize)
  }

  render() {
    return (
      <span>
        {this.state.windowWidth} x {this.state.windowHeight}
      </span>
    );
  }
}

フック

import React, { useEffect, useState } from "react";

let App = () => {
  const [windowWidth, setWindowWidth] = useState(0);
  const [windowHeight, setWindowHeight] = useState(0);
  let resizeWindow = () => {
    setWindowWidth(window.innerWidth);
    setWindowHeight(window.innerHeight);
  };

  useEffect(() => {
    resizeWindow();
    window.addEventListener("resize", resizeWindow);
    return () => window.removeEventListener("resize", resizeWindow);
  }, []);

  return (
    <div>
      <span>
        {windowWidth} x {windowHeight}
      </span>
    </div>
  );
};

4
これはすばらしい簡潔な答えですが、AFAICTには1つのバグがあります。私が誤っていない限り、::バインド演算子は適用されるたびに新しい値を返します。そのため、removeEventListener最初に渡されたものとは異なる関数を渡してしまうため、イベントリスナーは実際には登録解除されませんaddEventListener
natevw

21

React 16.8以降、フックを使用できます!

/* globals window */
import React, { useState, useEffect } from 'react'
import _debounce from 'lodash.debounce'

const Example = () => {
  const [width, setWidth] = useState(window.innerWidth)

  useEffect(() => {
    const handleResize = _debounce(() => setWidth(window.innerWidth), 100)

    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize);
    }
  }, [])

  return <>Width: {width}</>
}

13

2018年の編集:Reactがコンテキストに対するファーストクラスのサポートを追加


私は、この特定の問題を対象とする一般的な答えを出そうとしますが、より一般的な問題も取り上げます。

副作用ライブラリを気にしない場合は、Packeryのようなものを使用できます

Fluxを使用する場合は、ウィンドウプロパティを含むストアを作成して、毎回ウィンドウオブジェクトをクエリする必要なく純粋なレンダリング関数を維持できます。

レスポンシブなWebサイトを構築したいが、メディアクエリよりもReactインラインスタイルを使用したい場合や、HTML / JSの動作をウィンドウの幅に応じて変更したい場合は、以下をお読みください。

Reactコンテキストとは何か、そしてなぜ私はそれについて話すのか

反応コンテキスト anはパブリックAPIにはなく、コンポーネントの階層全体にプロパティを渡すことができます。

Reactコンテキストは、変更されないものをアプリ全体に渡す場合に特に便利です(mixinを介して多くのFluxフレームワークで使用されます)。これを使用して、アプリのビジネスの不変条件を格納できます(接続されたuserIdのように、どこでも使用できるようになります)。

しかし、変化する可能性のあるものを保存するためにも使用できます。問題は、コンテキストが変更されると、それを使用するすべてのコンポーネントを再レンダリングする必要があり、再レンダリングが容易ではないことです。多くの場合、最善の解決策は、新しいコンテキストでアプリ全体をアンマウント/再マウントすることです。forceUpdateは再帰的ではないことに注意してください。

したがって、理解できるように、コンテキストは実用的ですが、変更するとパフォーマンスに影響するため、あまり頻繁に変更しないでください。

コンテキストに何を置くか

  • 不変条件:接続されたuserId、sessionTokenなど。
  • あまり変わらないもの

頻繁に変更されないものは次のとおりです。

現在のユーザー言語

頻繁に変更されることはありません。変更されると、アプリ全体が翻訳されるため、すべてを再レンダリングする必要があります。ホットな言語変更の非常に優れたユースケース

ウィンドウのプロパティ

幅と高さは頻繁には変更されませんが、レイアウトや動作を変更する必要がある場合があります。レイアウトについては、CSSメディアクエリを使用して簡単にカスタマイズできる場合もありますが、そうではなく、別のHTML構造が必要になる場合もあります。動作については、JavaScriptでこれを処理する必要があります。

すべてのサイズ変更イベントですべてを再レンダリングしたくないので、サイズ変更イベントをデバウンスする必要があります。

あなたの問題について私が理解しているのは、画面の幅に応じて表示するアイテムの数を知りたいということです。したがって、最初にレスポンシブなブレークポイントを定義する必要があります、さまざまなレイアウトタイプの数を列挙する必要があります。

例えば:

  • レイアウト "1col"、幅<= 600
  • レイアウト "2col"、600 <幅<1000
  • レイアウト "3col"、1000 <=幅

サイズ変更イベント(デバウンス)では、ウィンドウオブジェクトをクエリすることで、現在のレイアウトタイプを簡単に取得できます。

次に、レイアウトタイプを以前のレイアウトタイプと比較し、変更された場合は、新しいコンテキストでアプリを再レンダリングします。これにより、ユーザーがサイズ変更イベントをトリガーしたが、実際にはアプリが再レンダリングされないようにすることができます。レイアウトタイプは変更されていないため、必要な場合にのみ再レンダリングします。

それができたら、アプリ内のレイアウトタイプ(コンテキストからアクセス可能)を使用して、HTML、動作、CSSクラスをカスタマイズできます... Reactレンダー関数内のレイアウトタイプがわかっているため、インラインスタイルを使用してレスポンシブなWebサイトを安全に作成でき、メディアクエリをまったく必要としません。

Fluxを使用する場合、Reactコンテキストの代わりにストアを使用できますが、アプリに多くのレスポンシブコンポーネントがある場合は、コンテキストを使用する方が簡単でしょう。


10

私は@senornestorのソリューションを使用していますが、完全に正しくするには、イベントリスナーも削除する必要があります。

componentDidMount() {
    window.addEventListener('resize', this.handleResize);
}

componentWillUnmount(){
    window.removeEventListener('resize', this.handleResize);
}

handleResize = () => {
    this.forceUpdate();
};

それ以外の場合は、警告が表示されます。

警告:forceUpdate(...):マウントされたコンポーネントまたはマウントされたコンポーネントのみを更新できます。これは通常、マウントされていないコンポーネントでforceUpdate()を呼び出したことを意味します。これはノーオペレーションです。XXXコンポーネントのコードを確認してください。


1
次の理由で警告が表示されます。実行しているのは悪い習慣です。render()関数は、propsとstateの純粋な関数である必要があります。あなたのケースでは、状態で新しいサイズを保存する必要があります。
zoran404

7

上記のすべての回答をスキップして、react-dimensions高次コンポーネントの使用を開始します。

https://github.com/digidem/react-dimensions

単純な追加importや関数呼び出しを、あなたがアクセスすることができますthis.props.containerWidthし、this.props.containerHeightあなたのコンポーネントインチ

// Example using ES6 syntax
import React from 'react'
import Dimensions from 'react-dimensions'

class MyComponent extends React.Component {
  render() (
    <div
      containerWidth={this.props.containerWidth}
      containerHeight={this.props.containerHeight}
    >
    </div>
  )
}

export default Dimensions()(MyComponent) // Enhanced component

1
これはウィンドウのサイズではなく、コンテナーのサイズを示します。
mjtamlyn 2016年

3
はい、それがすべてのポイントです。ウィンドウのサイズを見つけるのは簡単です。コンテナーのサイズを見つけるのははるかに難しく、Reactコンポーネントにとってはさらに便利です。の最新バージョンはreact-dimensions、プログラムで変更された寸法でも機能します(たとえば、divのサイズが変更され、コンテナーのサイズに影響するため、サイズを更新する必要があります)。Ben Alpertの回答は、ブラウザウィンドウのサイズ変更イベントでのみ役立ちます。ここを参照してください:github.com/digidem/react-dimensions/issues/4
MindJuice

1
react-dimensionsウィンドウのサイズの変更、フレックスボックスのレイアウトの変更、JavaScriptのサイズ変更による変更を処理します。それでカバーできると思います。適切に処理できない例はありますか?
MindJuice 2016年

2
ウィンドウのサイズを取得するのは簡単です。そのためのライブラリは必要ありません:window.innerWidthwindow.innerHeightreact-dimensions問題のより重要な部分を解決し、ウィンドウのサイズが変更されたとき(およびコンテナーのサイズが変更されたとき)にレイアウトコードをトリガーします。
MindJuice 2016年

1
このプロジェクトはもはや積極的に維持されていません。
Parabolord

7

このコードは、新しいReactコンテキストAPIを使用しています

  import React, { PureComponent, createContext } from 'react';

  const { Provider, Consumer } = createContext({ width: 0, height: 0 });

  class WindowProvider extends PureComponent {
    state = this.getDimensions();

    componentDidMount() {
      window.addEventListener('resize', this.updateDimensions);
    }

    componentWillUnmount() {
      window.removeEventListener('resize', this.updateDimensions);
    }

    getDimensions() {
      const w = window;
      const d = document;
      const documentElement = d.documentElement;
      const body = d.getElementsByTagName('body')[0];
      const width = w.innerWidth || documentElement.clientWidth || body.clientWidth;
      const height = w.innerHeight || documentElement.clientHeight || body.clientHeight;

      return { width, height };
    }

    updateDimensions = () => {
      this.setState(this.getDimensions());
    };

    render() {
      return <Provider value={this.state}>{this.props.children}</Provider>;
    }
  }

その後、次のように、コード内のどこでも使用できます。

<WindowConsumer>
  {({ width, height }) =>  //do what you want}
</WindowConsumer>

6

必ずしも再レンダリングを強制する必要はありません。

これはOPには役立ちませんが、私の場合は、キャンバスのwidthおよびheight属性を更新するだけで済みました(CSSでは実行できません)。

次のようになります。

import React from 'react';
import styled from 'styled-components';
import {throttle} from 'lodash';

class Canvas extends React.Component {

    componentDidMount() {
        window.addEventListener('resize', this.resize);
        this.resize();
    }

    componentWillUnmount() {
        window.removeEventListener('resize', this.resize);
    }

    resize = throttle(() => {
        this.canvas.width = this.canvas.parentNode.clientWidth;
        this.canvas.height = this.canvas.parentNode.clientHeight;
    },50)

    setRef = node => {
        this.canvas = node;
    }

    render() {
        return <canvas className={this.props.className} ref={this.setRef} />;
    }
}

export default styled(Canvas)`
   cursor: crosshair;
`

5

これが最善の方法かどうかはわかりませんが、私にとってうまくいったのは最初にストアを作成することでした。私はそれをWindowStoreと呼びました。

import {assign, events} from '../../libs';
import Dispatcher from '../dispatcher';
import Constants from '../constants';

let CHANGE_EVENT = 'change';
let defaults = () => {
    return {
        name: 'window',
        width: undefined,
        height: undefined,
        bps: {
            1: 400,
            2: 600,
            3: 800,
            4: 1000,
            5: 1200,
            6: 1400
        }
    };
};
let save = function(object, key, value) {
    // Save within storage
    if(object) {
        object[key] = value;
    }

    // Persist to local storage
    sessionStorage[storage.name] = JSON.stringify(storage);
};
let storage;

let Store = assign({}, events.EventEmitter.prototype, {
    addChangeListener: function(callback) {
        this.on(CHANGE_EVENT, callback);
        window.addEventListener('resize', () => {
            this.updateDimensions();
            this.emitChange();
        });
    },
    emitChange: function() {
        this.emit(CHANGE_EVENT);
    },
    get: function(keys) {
        let value = storage;

        for(let key in keys) {
            value = value[keys[key]];
        }

        return value;
    },
    initialize: function() {
        // Set defaults
        storage = defaults();
        save();
        this.updateDimensions();
    },
    removeChangeListener: function(callback) {
        this.removeListener(CHANGE_EVENT, callback);
        window.removeEventListener('resize', () => {
            this.updateDimensions();
            this.emitChange();
        });
    },
    updateDimensions: function() {
        storage.width =
            window.innerWidth ||
            document.documentElement.clientWidth ||
            document.body.clientWidth;
        storage.height =
            window.innerHeight ||
            document.documentElement.clientHeight ||
            document.body.clientHeight;
        save();
    }
});

export default Store;

次に、このストアをコンポーネントで使用しました。

import WindowStore from '../stores/window';

let getState = () => {
    return {
        windowWidth: WindowStore.get(['width']),
        windowBps: WindowStore.get(['bps'])
    };
};

export default React.createClass(assign({}, base, {
    getInitialState: function() {
        WindowStore.initialize();

        return getState();
    },
    componentDidMount: function() {
        WindowStore.addChangeListener(this._onChange);
    },
    componentWillUnmount: function() {
        WindowStore.removeChangeListener(this._onChange);
    },
    render: function() {
        if(this.state.windowWidth < this.state.windowBps[2] - 1) {
            // do something
        }

        // return
        return something;
    },
    _onChange: function() {
        this.setState(getState());
    }
}));

参考までに、これらのファイルは部分的にトリミングされました。


1
ストアの状態は、ディスパッチされたアクションに応答してのみ変化する必要があります。これは間違いなくこれを行うための良い方法ではありません。
霜降りの素晴らしい2016

2
@frostymarvelousは確かに、他の回答と同じようにコンポーネントに移動した方がよいでしょう。
David Sinclair

@DavidSinclairまたはさらに良いことに、onresizeをディスパッチできWindowResizedActionます。
John Weisz 2016年

1
これはやりすぎです。
Jason Rice

5

私はこれが回答されたことを知っていますが、私の解決策を最高の回答として共有すると思っていましたが、素晴らしいですが、今は少し古いかもしれません。

    constructor (props) {
      super(props)

      this.state = { width: '0', height: '0' }

      this.initUpdateWindowDimensions = this.updateWindowDimensions.bind(this)
      this.updateWindowDimensions = debounce(this.updateWindowDimensions.bind(this), 200)
    }

    componentDidMount () {
      this.initUpdateWindowDimensions()
      window.addEventListener('resize', this.updateWindowDimensions)
    }

    componentWillUnmount () {
      window.removeEventListener('resize', this.updateWindowDimensions)
    }

    updateWindowDimensions () {
      this.setState({ width: window.innerWidth, height: window.innerHeight })
    }

実際の唯一の違いは、リサイズイベントでupdateWindowDimensionsをデバウンスし(200ミリ秒ごとにのみ実行)、パフォーマンスを少し向上させていますが、ComponentDidMountで呼び出されたときにデバウンスしません。

マウントが頻繁に行われている状況では、デバウンスによってマウントがかなり遅くなることがあることがわかりました。

ほんの少しの最適化ですが、それが誰かに役立つことを願っています!


initUpdateWindowDimensionsメソッドの定義はどこにありますか?
Matt

これはコンストラクタで定義されています:)コンポーネントにバインドされたupdateWindowDimensionsですが、デバウンスはありません。
Matt Wills

3

使用するforceUpdate@senornestorのソリューションとresize、コンポーネントのマウント解除時にイベントリスナーを削除する@gkriのソリューションを改善するだけです。

  1. サイズ変更の呼び出しを抑制する(またはデバウンスする)ことを忘れないでください
  2. bind(this)コンストラクタで確認してください
import React from 'react'
import { throttle } from 'lodash'

class Foo extends React.Component {
  constructor(props) {
    super(props)
    this.resize = throttle(this.resize.bind(this), 100)
  }

  resize = () => this.forceUpdate()

  componentDidMount() {
    window.addEventListener('resize', this.resize)
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.resize)
  }

  render() {
    return (
      <div>{window.innerWidth} x {window.innerHeight}</div>
    )
  }
}

別の方法は、代わりに単に「ダミー」状態を使用することですforceUpdate

import React from 'react'
import { throttle } from 'lodash'

class Foo extends React.Component {
  constructor(props) {
    super(props)
    this.state = { foo: 1 }
    this.resize = throttle(this.resize.bind(this), 100)
  }

  resize = () => this.setState({ foo: 1 })

  componentDidMount() {
    window.addEventListener('resize', this.resize)
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.resize)
  }

  render() {
    return (
      <div>{window.innerWidth} x {window.innerHeight}</div>
    )
  }
}

2
componentDidMount() {

    // Handle resize
    window.addEventListener('resize', this.handleResize);
}




handleResize = () => {
    this.renderer.setSize(this.mount.clientWidth, this.mount.clientHeight);
    this.camera.aspect = this.mount.clientWidth / this.mount.clientHeight;
    this.camera.updateProjectionMatrix();
};

サイズ変更イベント関数のみを定義する必要があります。

次に、レンダラーのサイズ(キャンバス)を更新し、カメラに新しいアスペクト比を割り当てます。

アンマウントとリモートアウトは私の考えではクレイジーなソリューションです...

以下は必要に応じてマウントです。

            <div
                className={this.state.canvasActive ? 'canvasContainer isActive' : 'canvasContainer'}
                ref={mount => {
                    this.mount = mount;
                }}
            />

2

私が使用して見つけたこのかなりクールなものを共有したかった window.matchMedia

const mq = window.matchMedia('(max-width: 768px)');

  useEffect(() => {
    // initial check to toggle something on or off
    toggle();

    // returns true when window is <= 768px
    mq.addListener(toggle);

    // unmount cleanup handler
    return () => mq.removeListener(toggle);
  }, []);

  // toggle something based on matchMedia event
  const toggle = () => {
    if (mq.matches) {
      // do something here
    } else {
      // do something here
    }
  };

.matches ウィンドウが指定されたmax-width値より高いか低い場合、trueまたはfalseを返します。これは、ブール値が変更されたときにmatchMediaが1回だけ発生するため、リスナーを調整する必要がないことを意味します。

私のコードは簡単に調整してuseState、ブール値のmatchMediaの戻り値を保存し、条件付きでコンポーネントをレンダリングしたり、アクションを実行したりするために含めることができます。


1

それをクラス構文で機能させるには、コンストラクターで「this」にバインドする必要がありました

class MyComponent extends React.Component {
  constructor(props) {
    super(props)
    this.resize = this.resize.bind(this)      
  }
  componentDidMount() {
    window.addEventListener('resize', this.resize)
  }
  componentWillUnmount() {
    window.removeEventListener('resize', this.resize)
  }
}

1

回答ありがとうございます。これが私のReact + Recomposeです。これは、コンポーネントのwindowHeightおよびwindowWidthプロパティを含む高次関数です。

const withDimensions = compose(
 withStateHandlers(
 ({
   windowHeight,
   windowWidth
 }) => ({
   windowHeight: window.innerHeight,
   windowWidth: window.innerWidth
 }), {
  handleResize: () => () => ({
    windowHeight: window.innerHeight,
    windowWidth: window.innerWidth
  })
 }),
 lifecycle({
   componentDidMount() {
   window.addEventListener('resize', this.props.handleResize);
 },
 componentWillUnmount() {
  window.removeEventListener('resize');
 }})
)

1

https://github.com/renatorib/react-sizesは、優れたパフォーマンスを維持しながらこれを行うHOCです。

import React from 'react'
import withSizes from 'react-sizes'

@withSizes(({ width }) => ({ isMobile: width < 480 }))
class MyComponent extends Component {
  render() {
    return <div>{this.props.isMobile ? 'Is Mobile' : 'Is Not Mobile'}</div>
  }
}

export default MyComponent

0

この理由から、CSSまたはJSONファイルデータからこのデータを使用し、このデータをthis.state({width: "some value"、height: "some value"}); または、レスポンシブなショー画像が必要な場合は、セルフワークで幅画面データのデータを使用するコードを記述します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.