Como faço para o React renderizar novamente a exibição quando a janela do navegador é redimensionada?
fundo
Eu tenho alguns blocos que quero fazer o layout individualmente na página, mas também quero que eles sejam atualizados quando a janela do navegador mudar. O resultado final será algo como o layout do Pinterest de Ben Holland , mas escrito usando o React e não apenas o jQuery. Ainda estou longe.
Código
Aqui está o meu aplicativo:
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')
)
Então eu tenho o Block
componente (equivalente a um Pin
no exemplo acima do 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>
);
}
});
e a lista / coleção de 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>
);
}
});
Questão
Devo adicionar o redimensionamento da janela do jQuery? Se sim, onde?
$( window ).resize(function() {
// re-render the component
});
Existe uma maneira mais "reagir" de fazer isso?
fonte
this.updateDimensions
passado paraaddEventListener
é apenas uma referência de função simples que não terá valor parathis
quando chamado. Uma função anônima ou uma chamada .bind () deve ser usada para adicionarthis
ou entendi mal?this
para qualquer método definido diretamente no componente.innerHeight
einnerWidth
dewindow
. E você pode pularcomponentWillMount
se usargetInitialState
para definirheight
ewidth
.::
sintaxe de ligação não está disponível no momento sitepoint.com/bind-javascripts-this-keyword-react "o operador de ligação (: :) não fará parte do ES7, pois o conjunto de recursos do ES7 foi congelado em fevereiro , o operador de ligação é uma proposta para ES8 "@SophieAlpert está certa, +1, eu apenas quero fornecer uma versão modificada de sua solução, sem jQuery , com base nesta resposta .
fonte
Uma solução muito simples:
fonte
componentWillUnmount()
!forceUpdate
é aplicado condicionalmenteÉ um exemplo simples e curto de uso do es6 sem o jQuery.
ganchos
fonte
::
operador de ligação retornará um novo valor cada vez que for aplicado. Portanto, seu ouvinte de evento não será realmente registrado, pois vocêremoveEventListener
acaba passando uma função diferente da que foi originalmente transmitidaaddEventListener
.A partir do React 16.8, você pode usar Hooks !
fonte
Edit 2018 : now React tem suporte de primeira classe para o contexto
Vou tentar dar uma resposta genérica, que atinja esse problema específico, mas também um problema mais geral.
Se você não se importa com as bibliotecas de efeitos colaterais, pode simplesmente usar algo como Packery
Se você usar o Flux, poderá criar um armazenamento que contenha as propriedades da janela para manter uma função de renderização pura sem precisar consultar o objeto da janela toda vez.
Em outros casos em que você deseja criar um site responsivo, mas prefere Reagir estilos embutidos a consultas de mídia ou deseja que o comportamento HTML / JS mude de acordo com a largura da janela, continue lendo:
O que é o contexto React e por que eu falo sobre isso
O contexto de reação an não está na API pública e permite passar propriedades para toda uma hierarquia de componentes.
O contexto de reação é particularmente útil para passar para todo o aplicativo coisas que nunca mudam (é usado por muitas estruturas do Flux através de um mixin). Você pode usá-lo para armazenar invariantes de negócios de aplicativos (como o userId conectado, para que esteja disponível em qualquer lugar).
Mas também pode ser usado para armazenar coisas que podem mudar. O problema é que, quando o contexto muda, todos os componentes que o utilizam devem ser renderizados novamente e não é fácil fazê-lo, a melhor solução é desmontar / remontar o aplicativo inteiro com o novo contexto. Lembre-se de forceUpdate não é recursivo .
Então, como você entende, o contexto é prático, mas há um impacto no desempenho quando muda, portanto, não deve mudar com muita frequência.
O que colocar no contexto
Aqui estão as coisas que não mudam frequentemente:
O idioma atual do usuário :
Ele não muda com muita frequência e, quando muda, como todo o aplicativo é traduzido, precisamos renderizar tudo novamente: uma ótima maneira de mudar de idioma
As propriedades da janela
A largura e a altura não mudam frequentemente, mas quando fazemos nosso layout e comportamento, talvez seja necessário adaptar-se. Às vezes, para o layout, é fácil personalizar com mediaqueries CSS, mas às vezes não é e requer uma estrutura HTML diferente. Para o comportamento, você deve lidar com isso com Javascript.
Você não deseja renderizar tudo novamente em todos os eventos de redimensionamento, portanto, é necessário renunciar aos eventos de redimensionamento.
O que eu entendo do seu problema é que você deseja saber quantos itens serão exibidos de acordo com a largura da tela. Portanto, você deve primeiro definir pontos de interrupção responsivos e enumerar o número de diferentes tipos de layout que você pode ter.
Por exemplo:
Nos eventos de redimensionamento (rejeitados), é possível obter facilmente o tipo de layout atual consultando o objeto da janela.
Em seguida, você pode comparar o tipo de layout com o tipo de layout anterior e, se ele foi alterado, renderize novamente o aplicativo com um novo contexto: isso permite evitar a renderização novamente do aplicativo quando o usuário acionar eventos de redimensionamento, mas na verdade o o tipo de layout não foi alterado, portanto, você só renderiza novamente quando necessário.
Depois disso, você pode simplesmente usar o tipo de layout dentro do seu aplicativo (acessível através do contexto) para personalizar o HTML, o comportamento, as classes CSS ... Você conhece o seu tipo de layout na função React render, para que você possa pode escrever sites responsivos com segurança usando estilos em linha e não precisa de consultas de mídia.
Se você usa o Flux, pode usar uma loja em vez do contexto React, mas se seu aplicativo tiver muitos componentes responsivos, talvez seja mais fácil usar o contexto?
fonte
Eu uso a solução do @senornestor, mas, para estar totalmente correto, você também precisa remover o ouvinte de evento:
Caso contrário, você receberá o aviso:
fonte
Eu pularia todas as respostas acima e começaria a usar o
react-dimensions
componente de ordem superior.https://github.com/digidem/react-dimensions
Basta adicionar uma
import
chamada simples e uma função, e você pode acessarthis.props.containerWidth
ethis.props.containerHeight
em seu componente.fonte
react-dimensions
even funciona para dimensões alteradas programaticamente (por exemplo, o tamanho de uma div alterado, o que afeta o tamanho do seu contêiner, portanto, é necessário atualizar o tamanho). A resposta de Ben Alpert ajuda apenas na janela do navegador a redimensionar eventos. Veja aqui: github.com/digidem/react-dimensions/issues/4react-dimensions
lida com alterações no tamanho da janela, alterações no layout da caixa flexível e alterações devido ao redimensionamento do JavaScript. Eu acredito que isso é suficiente. Você tem um exemplo que ele não lida corretamente?window.innerWidth
,window.innerHeight
.react-dimensions
resolve a parte mais importante do problema e também aciona o código do layout quando a janela é redimensionada (assim como quando o tamanho do contêiner é alterado).Este código está usando a nova API de contexto do React :
Em seguida, você pode usá-lo onde quiser no seu código assim:
fonte
Você não precisa necessariamente forçar uma nova renderização.
Isso pode não ajudar o OP, mas, no meu caso, eu só precisava atualizar os atributos
width
eheight
na minha tela (o que você não pode fazer com CSS).Se parece com isso:
fonte
Não tenho certeza se essa é a melhor abordagem, mas o que funcionou para mim foi a criação de uma loja, chamei de WindowStore:
Então eu usei essa loja nos meus componentes, mais ou menos assim:
Para sua informação, esses arquivos foram parcialmente cortados.
fonte
onresize
poderia enviar aWindowResizedAction
.Sei que isso foi respondido, mas pensei em compartilhar minha solução, pois a resposta principal, embora ótima, agora pode estar um pouco desatualizada.
A única diferença realmente é que estou denunciando (executando apenas a cada 200ms) o updateWindowDimensions no evento redimensionar para aumentar um pouco o desempenho, MAS não o denuncio quando é chamado em ComponentDidMount.
Eu estava descobrindo que o rebounce tornava bastante lento a montagem às vezes, se você tem uma situação em que ela está montando com frequência.
Apenas uma pequena otimização, mas espero que ajude alguém!
fonte
initUpdateWindowDimensions
método?Apenas para melhorar a solução do @ senornestor a ser usada
forceUpdate
e a solução do @ gkri para remover oresize
ouvinte de eventos na desmontagem de componentes:bind(this)
no construtorOutro método é usar apenas um estado "fictício" em vez de
forceUpdate
:fonte
Só é necessário definir a função de evento de redimensionamento.
Atualize o tamanho dos renderizadores (tela), atribua uma nova proporção para a câmera.
Desmontar e remontar é uma solução louca na minha opinião ....
abaixo está o suporte, se necessário.
fonte
Queria compartilhar essa coisa bem legal que acabei de encontrar usando
window.matchMedia
.matches
retornará true ou false se a janela for maior ou menor que o valor de largura máxima especificado, isso significa que não há necessidade de limitar o ouvinte, pois o matchMedia é acionado apenas uma vez quando o booleano for alterado.Meu código pode ser facilmente ajustado para incluir
useState
para salvar os retornos booleanos matchMedia e usá-lo para renderizar condicionalmente um componente, ação de disparo etc.fonte
Tinha que vinculá-lo a 'this' no construtor para fazê-lo funcionar com a sintaxe da classe
fonte
Obrigado a todos pelas respostas. Aqui está o meu React + Recompose . É uma função de alta ordem que inclui as propriedades
windowHeight
ewindowWidth
para o componente.fonte
https://github.com/renatorib/react-sizes é um HOC para fazer isso, mantendo um bom desempenho.
fonte
Por esse motivo, é melhor se você usar esses dados dos dados do arquivo CSS ou JSON e, com esses dados, definir um novo estado com this.state ({width: "some value", height: "some value"}); ou escrever código que use dados de dados da tela de largura no trabalho por conta própria, se desejar exibir imagens responsivas
fonte