Bagaimana saya bisa mendapatkan React untuk merender ulang tampilan ketika jendela browser diubah ukurannya?
Latar Belakang
Saya memiliki beberapa blok yang ingin saya tata letak satu per satu di halaman, namun saya juga ingin mereka memperbarui ketika jendela browser berubah. Hasil akhirnya akan seperti tata letak Pinterest Ben Holland , tetapi ditulis menggunakan React bukan hanya jQuery. Aku masih jauh.
Kode
Inilah aplikasi saya:
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')
)
Lalu saya memiliki Block
komponen (setara dengan Pin
dalam contoh Pinterest di atas):
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>
);
}
});
dan daftar / koleksi 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>
);
}
});
Pertanyaan
Haruskah saya menambahkan ukuran jendela jQuery? Jika ya, dimana?
$( window ).resize(function() {
// re-render the component
});
Apakah ada cara lain "Bereaksi" untuk melakukan ini?
sumber
this.updateDimensions
diteruskan keaddEventListener
hanyalah referensi fungsi kosong yang tidak akan memiliki nilaithis
ketika dipanggil. Haruskah fungsi anonim, atau panggilan .bind () digunakan untuk menambahkanthis
, atau apakah saya salah paham?this
untuk metode yang didefinisikan langsung pada komponen.innerHeight
daninnerWidth
dariwindow
. Dan Anda dapat melewaticomponentWillMount
jika Anda gunakangetInitialState
untuk mengaturheight
danwidth
.::
sintaks bind keluar untuk saat ini sitepoint.com/bind-javascripts-this-keyword-react "operator bind (: :) tidak akan menjadi bagian dari ES7, karena set fitur ES7 dibekukan pada bulan Februari , operator mengikat adalah proposal untuk ES8 "@SophieAlpert benar, +1, saya hanya ingin memberikan versi modifikasi dari solusinya, tanpa jQuery , berdasarkan jawaban ini .
sumber
Solusi yang sangat sederhana:
sumber
componentWillUnmount()
!forceUpdate
diterapkan secara kondisionalIni adalah contoh sederhana dan singkat menggunakan es6 tanpa jQuery.
kait
sumber
::
operator bind mengembalikan nilai baru setiap kali diterapkan. Jadi pendengar acara Anda tidak akan benar-benar tidak terdaftar, karenaremoveEventListener
akhirnya Anda melewati fungsi yang berbeda dari yang semula diteruskanaddEventListener
.Pada React 16.8 Anda dapat menggunakan Hooks !
sumber
Sunting 2018 : sekarang Bereaksi memiliki dukungan kelas pertama untuk konteks
Saya akan mencoba memberikan jawaban umum, yang menargetkan masalah khusus ini tetapi juga masalah yang lebih umum.
Jika Anda tidak peduli dengan efek samping lib, Anda bisa menggunakan sesuatu seperti Packery
Jika Anda menggunakan Flux, Anda bisa membuat toko yang berisi properti jendela sehingga Anda menjaga fungsi render murni tanpa harus menanyakan objek jendela setiap kali.
Dalam kasus lain di mana Anda ingin membangun situs web responsif tetapi Anda lebih suka Bereaksi gaya inline ke kueri media, atau ingin perilaku HTML / JS berubah sesuai dengan lebar jendela, baca terus:
Apa konteks Bereaksi dan mengapa saya membicarakannya
Bereaksi konteks dan tidak dalam API publik dan mengizinkan untuk meneruskan properti ke seluruh hierarki komponen.
Konteks reaksi sangat berguna untuk diteruskan ke seluruh aplikasi Anda hal-hal yang tidak pernah berubah (digunakan oleh banyak kerangka kerja Flux melalui mixin). Anda dapat menggunakannya untuk menyimpan invarian bisnis aplikasi (seperti userId yang terhubung, sehingga tersedia di mana-mana).
Tetapi bisa juga digunakan untuk menyimpan hal-hal yang bisa berubah. Masalahnya adalah ketika konteksnya berubah, semua komponen yang menggunakannya harus di-render ulang dan tidak mudah untuk melakukannya, solusi terbaiknya adalah dengan meng-unmount / mengirim kembali seluruh aplikasi dengan konteks baru. Ingat forceUpdate tidak rekursif .
Jadi, seperti yang Anda pahami, konteksnya praktis, tetapi ada dampak kinerja saat berubah, jadi sebaiknya tidak terlalu sering berubah.
Apa yang dimasukkan ke dalam konteks
Berikut adalah hal-hal yang tidak sering berubah:
Bahasa pengguna saat ini :
Itu tidak berubah sangat sering, dan ketika itu terjadi, ketika seluruh aplikasi diterjemahkan kita harus membuat ulang semuanya: usecase perubahan bahas panas yang sangat bagus
Properti jendela
Lebar dan tinggi agar tidak sering berubah tetapi ketika kita melakukan tata letak dan perilaku kita mungkin harus beradaptasi. Untuk tata letak terkadang mudah untuk menyesuaikan dengan permintaan media CSS, tetapi kadang-kadang tidak dan membutuhkan struktur HTML yang berbeda. Untuk perilaku Anda harus menangani ini dengan Javascript.
Anda tidak ingin merender ulang semuanya di setiap acara pengubahan ukuran, jadi Anda harus membatalkan aktivitas pengubahan ukuran.
Yang saya mengerti tentang masalah Anda adalah bahwa Anda ingin tahu berapa banyak item yang akan ditampilkan sesuai dengan lebar layar. Jadi, Anda harus mendefinisikan breakpoints responsif terlebih dahulu , dan menyebutkan jumlah jenis tata letak yang berbeda yang dapat Anda miliki.
Sebagai contoh:
Pada mengubah ukuran acara (didebitkan), Anda dapat dengan mudah mendapatkan jenis tata letak saat ini dengan menanyakan objek jendela.
Kemudian Anda dapat membandingkan jenis tata letak dengan jenis tata letak sebelumnya, dan jika telah berubah, render ulang aplikasi dengan konteks baru: ini memungkinkan untuk menghindari rendering ulang aplikasi sama sekali ketika pengguna telah memicu mengubah ukuran acara tetapi sebenarnya tipe tata letak tidak berubah, jadi Anda hanya merender ulang saat diperlukan.
Setelah memilikinya, Anda cukup menggunakan jenis tata letak di dalam aplikasi Anda (dapat diakses melalui konteks) sehingga Anda dapat menyesuaikan kelas HTML, perilaku, kelas CSS ... Anda tahu jenis tata letak di dalam fungsi React render sehingga ini berarti Anda dapat dengan aman menulis situs web responsif dengan menggunakan gaya sebaris, dan tidak memerlukan mediaqueries sama sekali.
Jika Anda menggunakan Flux, Anda dapat menggunakan toko alih-alih konteks Bereaksi, tetapi jika aplikasi Anda memiliki banyak komponen responsif, mungkin lebih mudah menggunakan konteks?
sumber
Saya menggunakan solusi @senornestor, tetapi untuk sepenuhnya benar Anda harus menghapus pendengar acara juga:
Kalau tidak, Anda akan mendapatkan peringatan:
sumber
Saya akan melewati semua jawaban di atas dan mulai menggunakan
react-dimensions
Komponen Orde Tinggi.https://github.com/digidem/react-dimensions
Cukup tambahkan
import
panggilan fungsi dan sederhana , dan Anda dapat mengaksesthis.props.containerWidth
danthis.props.containerHeight
di komponen Anda.sumber
react-dimensions
bahkan berfungsi untuk dimensi yang diubah secara program (misalnya, ukuran div berubah, yang memengaruhi ukuran wadah Anda, jadi Anda perlu memperbarui ukuran Anda). Jawaban Ben Alpert hanya membantu di jendela browser mengubah ukuran acara. Lihat di sini: github.com/digidem/react-dimensions/issues/4react-dimensions
menangani perubahan dalam ukuran jendela, perubahan tata letak flexbox dan perubahan karena ukuran JavaScript. Saya pikir itu menutupinya. Apakah Anda memiliki contoh yang tidak ditangani dengan benar?window.innerWidth
,window.innerHeight
.react-dimensions
memecahkan bagian yang lebih penting dari masalah, dan juga memicu kode tata letak Anda ketika jendela diubah ukurannya (serta ketika ukuran wadah berubah).Kode ini menggunakan API konteks Bereaksi baru :
Maka Anda dapat menggunakannya di mana pun Anda inginkan dalam kode Anda seperti ini:
sumber
Anda tidak perlu memaksakan re-render.
Ini mungkin tidak membantu OP, tetapi dalam kasus saya, saya hanya perlu memperbarui
width
danheight
atribut di kanvas saya (yang tidak dapat Anda lakukan dengan CSS).Ini terlihat seperti ini:
sumber
Tidak yakin apakah ini pendekatan terbaik, tetapi yang berhasil bagi saya adalah pertama kali membuat Toko, saya menyebutnya WindowStore:
Lalu saya menggunakan toko itu di komponen saya, agak seperti ini:
FYI, file-file ini sebagian telah dipangkas.
sumber
onresize
bisa mengirim aWindowResizedAction
.Saya tahu ini telah dijawab tetapi saya pikir saya akan membagikan solusi saya sebagai jawaban teratas, meskipun hebat, sekarang mungkin sedikit ketinggalan jaman.
Satu-satunya perbedaan adalah saya melakukan debouncing (hanya menjalankan setiap 200 ms) updateWindowDimensions pada event resize untuk sedikit meningkatkan kinerja, TETAPI jangan debouncing ketika dipanggil ComponentDidMount.
Saya menemukan debounce membuatnya agak lambat untuk dipasang kadang-kadang jika Anda memiliki situasi di mana ia sering dipasang.
Hanya sedikit pengoptimalan tetapi harap ini membantu seseorang!
sumber
initUpdateWindowDimensions
metode?Hanya untuk meningkatkan solusi @ senornestor untuk digunakan
forceUpdate
dan solusi @ gkri untuk menghapusresize
pendengar acara pada komponen unmount:bind(this)
di konstruktorMetode lain adalah dengan menggunakan keadaan "dummy" alih-alih
forceUpdate
:sumber
Hanya perlu mendefinisikan fungsi ukuran acara.
Kemudian perbarui ukuran penyaji (kanvas), tetapkan rasio aspek baru untuk kamera.
Lepas dan remouting adalah solusi gila menurut saya ....
di bawah ini adalah mount jika diperlukan.
sumber
Ingin membagikan hal keren yang baru saja saya temukan menggunakan ini
window.matchMedia
.matches
akan mengembalikan benar atau salah jika jendela lebih tinggi atau lebih rendah dari nilai lebar-max yang ditentukan, ini berarti tidak perlu mencekik pendengar, karena matchMedia hanya menyala sekali ketika boolean berubah.Kode saya dapat dengan mudah disesuaikan untuk dimasukkan
useState
untuk menyimpan pengembalian boolean matchMedia, dan menggunakannya untuk membuat komponen, tindakan kebakaran, dll.sumber
Harus mengikatnya ke 'ini' di konstruktor untuk membuatnya bekerja dengan sintaks Kelas
sumber
Terima kasih atas jawabannya. Inilah React + Recompose saya . Ini adalah Fungsi Orde Tinggi yang mencakup
windowHeight
danwindowWidth
properti ke komponen.sumber
https://github.com/renatorib/react-sizes adalah HOC untuk melakukan ini sambil tetap mempertahankan kinerja yang baik.
sumber
Untuk alasan ini lebih baik adalah jika Anda menggunakan data ini dari data file CSS atau JSON, dan kemudian dengan menetapkan data ini status baru dengan this.state ({width: "some value", height: "some value"}); atau menulis kode yang menggunakan data data layar lebar dalam pekerjaan sendiri jika Anda ingin menampilkan gambar yang responsif
sumber