রিঅ্যাক্ট সহ ব্রাউজারের আকারে পুনর্নির্মাণের দৃশ্য


313

ব্রাউজার উইন্ডোটির আকার পরিবর্তন করা হলে আমি কীভাবে পুনরায় রেন্ডার করতে প্রতিক্রিয়া জানাতে পারি?

পটভূমি

আমার কিছু ব্লক রয়েছে যা আমি পৃষ্ঠায় স্বতন্ত্রভাবে বিন্যাস করতে চাই, তবে আমি যখন ব্রাউজার উইন্ডো পরিবর্তন হয় তখন সেগুলি আপডেট করতে চাই। একেবারে শেষ ফলাফলটি বেন হল্যান্ডের মতো কিছু হবে পিনটারেস্ট লেআউটের তবে প্রতিক্রিয়া ব্যবহার করে কেবল jQuery নয় written আমি এখনও একটি পথ বন্ধ।

কোড

এখানে আমার অ্যাপ্লিকেশন:

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 উদাহরণের সাথে সমান ):

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
});

এটি করার আরও একটি "প্রতিক্রিয়া" উপায় আছে?

উত্তর:


529

প্রতিক্রিয়া হুক ব্যবহার করে:

আপনি একটি কাস্টম হুক সংজ্ঞায়িত করতে পারেন যা উইন্ডো 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>;
}

এখানে সুবিধাটি হ'ল লজিকটি ইনপ্যাপসুলেটেড এবং আপনি উইন্ডোর আকারটি যে কোনও জায়গায় ব্যবহার করতে চান এই হুকটি ব্যবহার করতে পারেন।

প্রতিক্রিয়া ক্লাস ব্যবহার:

আপনি কম্পোনেন্টডিডমাউন্টে শুনতে পারেন, এই উপাদানটির মতো কিছু যা উইন্ডোটির মাত্রা (যেমন <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পাশ থেকে addEventListenerশুধু একটি খালি ফাংশন রেফারেন্স, যার জন্য কোনো মূল্য থাকবে thisযখন বলা হয়। কোনও বেনামি ফাংশন, বা একটি .bind () কলটি যুক্ত করতে ব্যবহার করা উচিত this, বা আমি ভুল বুঝেছি?
ফ্যাডেবি

24
@ ক্রিসডিউ আমি এখানে একটু দেরি করেছি, তবে অটো-বাইন্ডগুলি প্রতিক্রিয়া জানাব this উপাদানটিতে সরাসরি সংজ্ঞায়িত কোনও পদ্ধতির জন্য জানাতে হবে।
মিশেল টিলি

3
@ ম্যাটডেল হ্যাঁ, ইএস classes ক্লাসগুলি কেবলমাত্র সাধারণ ক্লাস, তাই তাদের সাথে কোনও স্বয়ংক্রিয় বাধ্যতামূলক নেই।
মিশেল টিলি

30
কোন jQuery প্রয়োজন নেই - ব্যবহার innerHeightএবং innerWidthথেকে window। আপনি সেট করতে এবং componentWillMountব্যবহার করতে পারলে আপনি এড়িয়ে যেতে পারেন । getInitialStateheightwidth
সিঘরোবট

2
মত @MattDell সৌন্দর্য ::বেঁধে সিনট্যাক্স এখন জন্য বাইরে sitepoint.com/bind-javascripts-this-keyword-react ( "বেঁধে অপারেটর: :) না ফেব্রুয়ারিতে নিথর ছিল, ES7 অংশ হতে যাচ্ছে যেমন ES7 সেট অতিরিক্ত বৈশিষ্ট্যগুলিও উপস্থিত রয়েছে , বাইন্ড অপারেটরটি ES8 এর জন্য প্রস্তাব ""
জারোদ স্মিথ

130

@ সোফিএলপার্ট ঠিক আছে, +1, আমি এই উত্তরটির উপর ভিত্তি করে জিকুয়েরি ছাড়াই তার সমাধানের একটি পরিবর্তিত সংস্করণ সরবরাহ করতে চাই ।

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 সম্পর্কিত পলফিলগুলি সেট আপ করবেন
nnnn

@nnn আপনি কি বিস্তারিত বলতে পারবেন? আমি স্বীকার করি আমি কেবল Chrome এ এটি পরীক্ষা করেছি। আপনি কি বলছেন উইন্ডো.এডএভেন্টলিস্টনার পলিফিল ছাড়া আইই তে কাজ করছে না?
আন্দ্রে পেনা

2
@andrerpena caniuse.com/#search=addeventlistener ইঙ্গিত করে ie8 এর সমস্যা হবে
nnnn

2
@nnnn। আমি দেখি. হ্যাঁ .. সুতরাং আমার সমাধান IE 8 এ কাজ করে না, তবে 9 থেকে :) এ কাজ করে। ধন্যবাদ।
আন্দ্রে পেনা

35
আসলেই কি কেউ আইই 8 সম্পর্কে চিন্তা করে? নাকি এটা কি শুধু অভ্যাস?
হিমশীতল

48

খুব সহজ সমাধান:

resize = () => this.forceUpdate()

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

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

12
ফোর্স আপডেটটি থ্রটল করতে ভুলবেন না বা এটি খুব চটকদার দেখাচ্ছে।
2snowman69

4
এছাড়াও শ্রোতা অপসারণ করতে ভুলবেন না componentWillUnmount()!
জেমার জোন্স 14

এটি থ্রোলেটড হলে এটি সেরা সমাধান। আমার অর্থ যদি forceUpdateশর্তাধীনভাবে প্রয়োগ করা হয়
asmmahmud

1
এটি ফোর্সড করা দরকার এমন ফোর্সআপডেট (জিনিসটি বলা হচ্ছে) নয়, এটি পুনরায় আকারের ইভেন্টের ফায়ারিং যা থ্রটল করা দরকার (জিনিসটি গুলি চালানো)। আপনি উইন্ডোটিকে বড় থেকে ছোট আকারে আকার দেওয়ার সাথে সাথে পুনরায় আকারের ইভেন্টগুলি প্রতিটি পিক্সেলটিতে প্রযুক্তিগতভাবে ডাকা যেতে পারে। যখন কোনও ব্যবহারকারী এটি দ্রুত করে, তখন এটি আপনার যত্নের চেয়ে বেশি ইভেন্ট। সবচেয়ে খারাপ, আপনি ইউআই থ্রেডটিকে জাভাস্ক্রিপ্ট থ্রেডে আবদ্ধ করছেন যার অর্থ আপনার অ্যাপ্লিকেশনটি মারাত্মকভাবে ধীরে ধীরে অনুভূতি পেতে শুরু করবে কারণ এটি প্রতিটি ইভেন্ট পৃথকভাবে পরিচালনা করার চেষ্টা করে।
2snowman69

1
প্রতি পিক্সালে পুনরায় আকার ফাংশনটি চালানোর পরিবর্তে, আপনি তরলতার মায়া দেওয়ার জন্য কিছুটা স্বল্প সময়ের মধ্যে এটি চালান যা আপনি সর্বদা প্রথম এবং শেষ ইভেন্টটি পরিচালনা করেন যা এইভাবে অনুভূত করে যে এটি পুনরায় আকারটি তরলভাবে পরিচালনা করছে।
2snowman69

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
এটি একটি দুর্দান্ত, সংক্ষিপ্ত উত্তর তবে এএএএএফসিটির একটি বাগ রয়েছে: আমি ভুল না হলে ::বাইন্ড অপারেটর প্রতিটিবার প্রয়োগ হওয়ার সাথে সাথে একটি নতুন মান প্রদান করে। সুতরাং আপনার ইভেন্ট শ্রোতা প্রকৃতপক্ষে নিবন্ধভুক্ত হবে না, যেহেতু আপনার শেষটি removeEventListenerমূলত যা দেওয়া হয়েছিল তার চেয়ে আলাদা ফাংশনটি শেষ করবে addEventListener
natevw

20

প্রতিক্রিয়া হিসাবে 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 সম্পাদনা করুন : এখন প্রতিক্রিয়াটির প্রসঙ্গে প্রথম শ্রেণির সমর্থন রয়েছে


আমি একটি জেনেরিক উত্তর দেওয়ার চেষ্টা করব, যা এই নির্দিষ্ট সমস্যাটিকে লক্ষ্য করে তবে আরও সাধারণ সমস্যাও।

আপনি যদি পার্শ্বপ্রতিক্রিয়াগুলির libs সম্পর্কে চিন্তা না করেন তবে আপনি কেবল প্যাকারি জাতীয় কিছু ব্যবহার করতে পারেন

আপনি যদি ফ্লাক্স ব্যবহার করেন তবে আপনি এমন একটি স্টোর তৈরি করতে পারেন যাতে উইন্ডোটির বৈশিষ্ট্য রয়েছে যাতে আপনি প্রতিবার উইন্ডো অবজেক্টটি অনুসন্ধান না করে খাঁটি রেন্ডার ফাংশন রাখতে পারেন।

অন্যান্য ক্ষেত্রে যেখানে আপনি একটি প্রতিক্রিয়াশীল ওয়েবসাইট বানাতে চান তবে আপনি মিডিয়া প্রশ্নের সাথে ইনলাইন শৈলীর প্রতিক্রিয়া পছন্দ করেন বা উইন্ডো প্রস্থ অনুযায়ী এইচটিএমএল / জেএস আচরণ পরিবর্তন করতে চান, পড়া চালিয়ে যান:

প্রতিক্রিয়া প্রসঙ্গ কী এবং আমি কেন এটি সম্পর্কে কথা বলি

প্রসঙ্গটি প্রতিক্রিয়া করুন একটি সর্বজনীন এপিআইতে নেই এবং উপাদানগুলির পুরো শ্রেণিবিন্যাসে সম্পত্তিগুলি পাস করার অনুমতি দেয়।

প্রতিক্রিয়া প্রসঙ্গে আপনার পুরো অ্যাপ্লিকেশনগুলিতে যা কখনও পরিবর্তন হয় না তা পাস করার জন্য বিশেষভাবে কার্যকর (এটি অনেকগুলি ফ্লাক্স ফ্রেমওয়ার্কগুলি মিক্সিনের মাধ্যমে ব্যবহার করে)। আপনি এটি অ্যাপ্লিকেশন ব্যবসায়ের আক্রমণকারীগুলিকে (সংযুক্ত ইউজারআইডের মতো, যাতে এটি সর্বত্র উপলব্ধ থাকে) সঞ্চয় করতে ব্যবহার করতে পারেন।

তবে এটি পরিবর্তন করতে পারে এমন জিনিসগুলি সঞ্চয় করতেও ব্যবহার করা যেতে পারে। সমস্যাটি হ'ল যখন প্রসঙ্গটি পরিবর্তিত হয়, সমস্ত উপাদান যা এটি ব্যবহার করে তা পুনরায় রেন্ডার করা উচিত এবং এটি করা সহজ নয়, সবচেয়ে ভাল সমাধানটি প্রায়শই নতুন প্রসঙ্গের সাথে পুরো অ্যাপটিকে আনমাউন্ট / পুনঃস্থাপন করা হয়। মনে রাখবেন ফোর্সআপডেট পুনরাবৃত্ত হয় না

সুতরাং আপনি যেমন বুঝতে পেরেছেন, প্রসঙ্গটি ব্যবহারিক, তবে এটি পরিবর্তিত হলে একটি কার্যকারিতা প্রভাব রয়েছে, সুতরাং এটি প্রায়শই প্রায়শই পরিবর্তন করা উচিত নয়।

প্রসঙ্গে কী রাখব

  • আক্রমণকারীরা: সংযুক্ত ইউজারআইডি, সেশন টোকেনের মতো, যাই হোক না কেন ...
  • যে জিনিসগুলি প্রায়শই পরিবর্তন হয় না

এখানে এমন জিনিস যা প্রায়শই পরিবর্তন হয় না:

বর্তমান ব্যবহারকারীর ভাষা :

এটি প্রায়শই পরিবর্তন হয় না এবং যখন এটি হয়, পুরো অ্যাপ্লিকেশনটির অনুবাদ হিসাবে আমাদের সমস্ত কিছু পুনরায় রেন্ডার করতে হবে: হট ল্যাঙ্গেজ পরিবর্তনের খুব সুন্দর ব্যবহার

উইন্ডো বৈশিষ্ট্য

প্রস্থ এবং উচ্চতা প্রায়শই পরিবর্তন করা যায় না তবে আমরা যখন করি আমাদের বিন্যাস এবং আচরণটি মানিয়ে নিতে পারে। লেআউটটির জন্য কখনও কখনও সিএসএস মিডিয়া প্রশ্নগুলির সাথে কাস্টমাইজ করা সহজ তবে কখনও কখনও এটি হয় না এবং এর জন্য আলাদা আলাদা HTML কাঠামো প্রয়োজন requires আচরণের জন্য আপনাকে জাভাস্ক্রিপ্টের সাহায্যে এটি পরিচালনা করতে হবে।

আপনি প্রতিটি আকার পরিবর্তনকারী ইভেন্টের সবকিছুকে পুনরায় রেন্ডার করতে চান না, তাই আপনাকে পুনরায় আকারের ইভেন্টগুলি ডাবনো করতে হবে।

আপনার সমস্যাটি সম্পর্কে আমি যা বুঝি তা হ'ল আপনি জানতে চান যে পর্দার প্রস্থ অনুসারে কতগুলি আইটেম প্রদর্শিত হবে। সুতরাং আপনার প্রথমে প্রতিক্রিয়াশীল ব্রেকপয়েন্টগুলি সংজ্ঞায়িত করতে হবে এবং আপনার হতে পারে বিভিন্ন লেআউট ধরণের সংখ্যা গণনা করতে হবে।

উদাহরণ স্বরূপ:

  • <= 600 প্রস্থের জন্য লেআউট "1col"
  • 600 <প্রস্থ <1000 এর জন্য লেআউট "2col"
  • 1000 <= প্রস্থের জন্য "3col" লেআউট

পুনরায় আকারের ইভেন্টগুলিতে (উত্সাহিত), আপনি উইন্ডো অবজেক্টটি অনুসন্ধান করে খুব সহজেই বর্তমান লেআউট প্রকারটি পেতে পারেন।

তারপরে আপনি পূর্বের লেআউট প্রকারের সাথে লেআউট প্রকারটি তুলনা করতে পারবেন এবং যদি এটি পরিবর্তিত হয়ে থাকে তবে অ্যাপটিকে নতুন প্রসঙ্গে পুনরায় রেন্ডার করুন: ব্যবহারকারী যখন পুনরায় আকার পরিবর্তন করতে বাড়াতে অনুমতি দেয় যখন ব্যবহারকারীর পুনরায় আকার পরিবর্তন করা ইভেন্টগুলি ঘটে তবে আসলে বিন্যাসের ধরণটি পরিবর্তিত হয়নি, তাই আপনি প্রয়োজন হলে কেবল পুনরায় রেন্ডার করুন।

এটি একবার হয়ে গেলে, আপনি কেবল আপনার অ্যাপ্লিকেশনের অভ্যন্তরে বিন্যাসের ধরণটি ব্যবহার করতে পারেন (প্রসঙ্গের মাধ্যমে অ্যাক্সেসযোগ্য) যাতে আপনি এইচটিএমএল, আচরণ, সিএসএস ক্লাসগুলি কাস্টমাইজ করতে পারেন ... আপনি প্রতিক্রিয়া রেন্ডার ফাংশনটির ভিতরে আপনার লেআউট প্রকারটি জানেন তাই এর অর্থ আপনার ইনলাইন স্টাইলগুলি ব্যবহার করে সুরক্ষিতভাবে প্রতিক্রিয়াশীল ওয়েবসাইটগুলি লিখতে পারে এবং মিডিয়া প্রশ্নগুলির কোনও প্রয়োজন হয় না।

আপনি যদি ফ্লাক্স ব্যবহার করেন তবে আপনি প্রতিক্রিয়া প্রসঙ্গে পরিবর্তে একটি স্টোর ব্যবহার করতে পারেন, তবে আপনার অ্যাপে যদি অনেক প্রতিক্রিয়াশীল উপাদান থাকে তবে এটি প্রসঙ্গটি ব্যবহার করা সহজ?


10

আমি @ এসেনরনেস্টারের সমাধানটি ব্যবহার করি তবে পুরোপুরি সঠিক হতে গেলে আপনাকে ইভেন্ট শ্রোতাদেরও মুছে ফেলতে হবে:

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

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

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

অন্যথায় আপনি সতর্কতা পাবেন:

সতর্কতা: জবরদস্তি (...): কেবল একটি মাউন্ট করা বা মাউন্টিং উপাদান আপডেট করতে পারে। এর অর্থ সাধারণত আপনি কোনও আনমাউন্টযুক্ত উপাদানগুলিতে ফোর্সআপডেট () বলে। এটি কোনও অপশন নয়। XXX উপাদানগুলির জন্য দয়া করে কোডটি পরীক্ষা করুন।


1
আপনি একটি কারণে সতর্কতা পেয়ে যাচ্ছেন: আপনি যা করছেন তা খারাপ অভ্যাস। আপনার রেন্ডার () ফাংশনটি প্রপস এবং রাজ্যের খাঁটি ফাংশন হওয়া উচিত। আপনার ক্ষেত্রে আপনার রাজ্যে নতুন আকারটি সংরক্ষণ করা উচিত।
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

3
হ্যাঁ, এটাই পুরো কথা। উইন্ডোটির আকার এটি তুচ্ছ। একটি ধারকটির আকার খুঁজে পাওয়া আরও শক্ত এবং একটি প্রতিক্রিয়া উপাদানটির জন্য আরও অনেক দরকারী। react-dimensionsএমনকি সর্বশেষতম সংস্করণ প্রোগ্রামগতভাবে পরিবর্তিত মাত্রাগুলির জন্য কাজ করে (উদাহরণস্বরূপ, একটি ডিভের আকার পরিবর্তিত হয়েছে, যা আপনার ধারকটির আকারকে প্রভাবিত করে, তাই আপনাকে নিজের আকার আপডেট করতে হবে)। বেন আল্পার্টের উত্তর কেবলমাত্র ব্রাউজার উইন্ডোতে ইভেন্টের আকার পরিবর্তন করতে সহায়তা করে। এখানে দেখুন: github.com/digidem/react-dimension/issues/4
MindJuice

1
react-dimensionsউইন্ডোটির আকারের পরিবর্তনগুলি, জাভাস্ক্রিপ্ট পুনরায় আকার দেওয়ার কারণে ফ্লেক্সবক্স লেআউট পরিবর্তন এবং পরিবর্তনগুলি পরিচালনা করে। আমি এটি আবরণ মনে করি। আপনার কী এমন উদাহরণ রয়েছে যা এটি সঠিকভাবে পরিচালনা করে না?
মাইন্ডজুইস 11:38

2
উইন্ডো আকার পেতে তুচ্ছ। এর জন্য কোনও লাইব্রেরির দরকার নেই: window.innerWidth, window.innerHeightreact-dimensionsসমস্যার আরও গুরুত্বপূর্ণ অংশটি সমাধান করে এবং উইন্ডোটি পুনরায় আকার দেওয়ার সাথে সাথে (পাশাপাশি ধারকটির আকার পরিবর্তন করার সময়) আপনার লেআউট কোডটিও ট্রিগার করে।
MindJuice

1
এই প্রকল্পটি আর সক্রিয়ভাবে পরিচালিত হচ্ছে না।
প্যারাবোলর্ড

7

এই কোডটি নতুন প্রতিক্রিয়া প্রসঙ্গ এপিআই ব্যবহার করছে :

  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

আপনাকে অগত্যা পুনরায় রেন্ডার করার দরকার নেই।

এটি ওপিকে সাহায্য করতে পারে না তবে আমার ক্ষেত্রে আমার ক্যানভাসে কেবলমাত্র বৈশিষ্ট্যগুলি widthএবং heightবৈশিষ্ট্যগুলি আপডেট করতে হবে (যা আপনি সিএসএস দিয়ে করতে পারবেন না)।

দেখে মনে হচ্ছে:

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

এটি সর্বোত্তম পন্থা কিনা তা নিশ্চিত নন, তবে আমার পক্ষে যা কাজ করেছিল তা প্রথমে একটি স্টোর তৈরি করা হয়েছিল, আমি এটিকে উইন্ডোস্টোর বলেছিলাম:

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
পাঠানো ক্রিয়াকলাপের প্রতিক্রিয়া হিসাবে কেবল স্টোরের রাজ্যের পরিবর্তন করা উচিত। এটি অবশ্যই এটি করার ভাল উপায় নয়।
হিমশীতল

2
@ ফ্রস্টাইমার্ভুলাস সত্যই, সম্ভবত অন্যান্য উত্তরের মতো আরও ভালভাবে উপাদানটিতে স্থানান্তরিত হয়েছে।
ডেভিড সিনক্লেয়ার

@ ডেভিড সিনক্লেয়ার বা আরও ভাল onresizeএটি প্রেরণ করতে পারে WindowResizedAction
জন ওয়েইজ

1
এটি ওভারকিল
জেসন রাইস

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

পার্থক্যটি আসলেই হ'ল আমি সম্পাদনাটি (মাত্র 200 মিমি চলমান) পুনরায় আকারের ইভেন্টে আপডেট উইন্ডোডাইমেনশনগুলি পারফরম্যান্স কিছুটা বাড়িয়ে তুলতে চাইছি, তবে যখন এটি কম্পোনেন্টডিডমাউন্টে ডাকা হবে তখন এটি ডিবেস করবেন না।

আমি যখন আবিষ্কার করছিলাম যে এটি প্রায়শই মাউন্ট হচ্ছে এমন কোনও পরিস্থিতি যদি কখনও কখনও ঘটে তবে এটি মাউন্ট করতে যথেষ্ট পিছিয়ে পড়েছে।

একটি সামান্য অপ্টিমাইজেশন তবে আশা করি এটি কারওর পক্ষে সহায়তা করবে!


initUpdateWindowDimensionsপদ্ধতির সংজ্ঞা কোথায় ?
ম্যাট

এটি কনস্ট্রাক্টরে সংজ্ঞায়িত করা হয়েছে :) এটি কেবলমাত্র উইন্ডো ডাইমেনশনগুলির সাথে আবদ্ধ আবশ্যক তবে ডিবাউন ছাড়াই।
ম্যাট উইলস

3

কেবলমাত্র @ সোনারেস্টর ব্যবহারের সমাধান forceUpdateএবং @ গিগরির সমাধানটি resizeউপাদান আনমাউন্ট থেকে ইভেন্ট শ্রোতাদের অপসারণের উন্নতির জন্য :

  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 উইন্ডোটি নির্দিষ্ট সর্বাধিক প্রস্থের মানের চেয়ে বেশি বা কম হলে সত্য বা মিথ্যা প্রত্যাবর্তন করবে, এর অর্থ শ্রোতাদের থ্রোটল করার দরকার নেই, কারণ বুলিয়ান পরিবর্তিত হলে ম্যাচমিডিয়া কেবল একবারে গুলি চালায়।

আমার কোডটি useStateবুলিয়ান ম্যাচমিডিয়া রিটার্নগুলি সংরক্ষণ করার জন্য সহজেই সামঞ্জস্য করা যায় এবং শর্তসাপেক্ষে এটি কোনও উপাদান, ফায়ার অ্যাকশন ইত্যাদি রেন্ডার করতে ব্যবহার করে can


1

এটি ক্লাস সিনট্যাক্সের সাথে কাজ করতে কন্সট্রাক্টরে এটি "এটি" এ আবদ্ধ করতে হয়েছিল

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

উত্তরের জন্য আপনি সমস্ত ধন্যবাদ। এখানে আমার প্রতিক্রিয়া + পুনরায় রচনা করুন । এটি একটি হাই অর্ডার ফাংশন যা এতে উপাদানটির বৈশিষ্ট্য 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 এখনও ভাল পারফরম্যান্স বজায় রেখে এটি করার জন্য এইচওসি।

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

এই কারণে আপনি যদি সিএসএস বা জেএসওন ফাইল ডেটা থেকে এই ডেটা ব্যবহার করেন এবং তারপরে এই স্ট্যাটাসটি দিয়ে এই স্টেটস ({প্রস্থ: "কিছু মান", উচ্চতা: "কিছু মান"}) সেট করা থাকে তবে এটি আরও ভাল better বা লিখিত কোড যারা স্ব কাজের ক্ষেত্রে প্রস্থের পর্দার ডেটা ব্যবহার করে যদি আপনি প্রতিক্রিয়াশীল শো চিত্রগুলি চান তবে wish

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.