Revolução do componente do React: como os fechamentos se tornaram a base dos componentes modernos da interface do usuário
Nota: Neste artigo, eu intencionalmente uso os termos de jargão “Fechamento” e “Variável”. A especificação do ECMAScript não define formalmente “fechamentos” – ele fala sobre ambientes lexicais e cadeias de escopo – e o que geralmente chamamos de “variáveis” são tecnicamente identificadores vinculados nos registros ambientais. Estou mantendo o jargão aqui porque é o que a comunidade usa e torna a discussão mais legível. Todo desenvolvedor do React escreveu centenas de fechamentos. Muitos não percebem como eles se tornaram centrais. Quando você escreve: const [count, setCount] = usestate (0); Digite o modo de saída do modo de tela cheia, você não está apenas gerenciando o estado – você está criando um fechamento que captura variáveis de seu escopo lexical. Quando a React introduziu os ganchos no final de 2018 (e os lançou no início de 2019), não nos deu apenas uma nova API. Ele mudou significativamente a arquitetura de componente da estrutura dos padrões baseados em classes para o fechamento. A Grande Migração: De aulas para fechamentos lembra -se dos velhos tempos? classe contador estende react.component {construtor (props) {super (props); this.state = {count: 0}; this.inCrement = this.Increment.bind (this); // O temido bind} increment () {this.setState ({count: this.state.count + 1}); } render () {return ; }} Digite o modo de saída do modo de tela full State de tela cheia vivida em instâncias de componentes. Métodos tiveram que ser vinculados. Os métodos do ciclo de vida foram espalhados pela classe. Era orientado a objetos, mas estava confuso. Então os ganchos chegaram: function contador () {const [count, setCount] = usestate (0); const increment = () => setCount (contagem + 1); retornar ; } Digite o limpador de modo de tela cheia da tela cheia, certo? Mas o que realmente está acontecendo aqui representa uma mudança fundamental na maneira como os componentes do React funcionam. Isso não é apenas açúcar sintático – é uma abordagem completamente diferente da arquitetura componentes. O que queremos dizer com “Arquitetura de componentes baseados em fechamento” para ser claro: o mecanismo principal da React-o concutido, o programador e o pipeline de renderização-permanece em grande parte inalterados. O que transformou foi como escrevemos e pensamos sobre os componentes. A arquitetura baseada em fechamento refere-se especificamente a como os componentes funcionais aproveitam a mecânica de fechamento do JavaScript para gerenciamento de estado, efeitos e manuseio de eventos. O React ainda usa os mesmos algoritmos virtuais de DIM Diffing, Fiber Architecture e agendando. Os fechamentos sempre existiram no React-manipuladores de eventos em linha, componentes de ordem superior e adereços de renderizar todos os usaram. Mas com ganchos, os fechamentos se tornaram o principal mecanismo de estado, efeito e gerenciamento de eventos dentro dos componentes. O estado do componente não vive dentro do fechamento. O React o armazena em suas estruturas de fibra interna. Cada renderização apenas cria um fechamento que lhe dá acesso ao instantâneo atual desse estado. Bem -vindo à fábrica de fechamento, todo componente funcional é essencialmente uma fábrica de fechamento. Quando o React chama sua função de componente, ele cria um fechamento que captura: os valores do estado atual acessados através de adereços de uso de uso passados para os valores de contexto do componente via USECONTEXT quaisquer variáveis da função de escopo externo UserProfile ({userId}) {const [user, setUser] = usestate (nulo); const tema = useContext (temeContext); // Este efeito é um fechamento que captura o UserID, o SetUser e o tema Useeffect (() => {FetchUser (UserID) .Then ((User) => {SetUser (User); // Captura de fechamento do SetUser do escopo externo});}, [userId]); // Este manipulador de eventos também é um fechamento const Handleedit = () => {editUser (usuário, tema); // captura o usuário e o tema}; retornar
; } Digite o modo de saída de tela cheia de tela cheia Cada renderização cria novos fechamentos com novas capturas. Enquanto o mecanismo de reconciliação da React se concentra na DIV virtual DIM e na coordenação de renderização, ele se baseia fortemente nesses fechamentos criados durante cada ciclo de renderização. A bela complexidade dos efeitos dos efeitos mostra a arquitetura de fechamento com mais clareza. Todoeffect de uso cria um fechamento que captura o estado do componente naquele momento: Function Timer () {const [count, setCount] = usestate (0); useeffect (() => {// Este fechamento captura o valor atual da contagem de const timer = setInterval (() => {console.log (“contagem atual:”, count); setCount (contagem + 1); // sempre adiciona 1 ao tempo de contagem capturado! []); // vazio deps = fechamento nunca atualiza o retorno
; } Digite o modo de saída do modo de tela completa Este código tem um bug – a armadilha clássica de “fechamento obsoleto”, que também pode acontecer com ouvintes de eventos, retornos de chamada assíncronos ou observadores que capturam variáveis antigas. O retorno de chamada do setInterval CATURA DE CANTRA DE Quando o efeito foi executado. Embora a contagem de mudanças no estado interno do React, o fechamento ainda vê o valor antigo porque o efeito (e seu fechamento) nunca re-executa. A correção? Inclua contagem em dependências (criando novos fechamentos) ou use uma função de atualizador: useefft (() => {const timer = setInterval (() => {setCount ((prev) => prev + 1); // sem dependência de fechamento da contagem}, 1000); return () => clearInterval (timer);}, []); // Seguro com depósito vazio Digite Modo de tela cheia Modo de tela cheia A arquitetura de fechamento da dança de dança de memória React cria desafios de memória exclusivos. Quando os componentes desmontam, a limpeza adequada é essencial para evitar vazamentos. Os fechamentos não bloqueiam a coleta de lixo por conta própria – eles são coletados como qualquer objeto – a menos que algo mais ainda tenha uma referência a eles. Os problemas surgem quando sistemas externos (temporizadores, assinaturas, ouvintes de eventos) continuam apontando para os fechamentos de renderizações antigas. Função DataSubscription ({userId}) {const [data, setData] = usestate (nulo); useeffect (() => {const Subscription = api.subScribe (userID, (newData) => {SetData (newData); // Referências de fechamento SetData para esta renderização}); // limpeza remove a referência do sistema externo Return () => Subscription.UnsubScribe (); [userId]); } Digite o modo de saída de tela cheia de tela cheia sem a limpeza: o objeto de assinatura mantém uma referência ao fechamento do retorno de chamada. Esse fechamento referencia o SetData, ligado à fibra desta instância do componente. Enquanto a assinatura viverem, o fechamento (e o componente) permanecerá na memória, mesmo que o componente desmontado. As funções de limpeza quebram esta corrente. Ao reagir desmonta um componente, ele chama todas as limpezas de efeito, removendo referências externas. Uma vez que nada mais aponta para o fechamento, o coletor de lixo pode recuperá -lo. Por que isso importa a maioria dos vazamentos de memória nos aplicativos React não vem do próprio reagir – eles vêm de efeitos que esquecem de limpar. Os vazamentos podem não ser óbvios em pequenos componentes, mas em escala (pense em painéis ao vivo, aplicativos de bate-papo ou UIs pesados de dados) eles somam, diminuindo a velocidade do navegador e drenando a memória. Saber que os fechamentos vivem enquanto tudo os referenciar deixar claro por que as funções de limpeza não são negociáveis. MEMOIZAÇÃO: Otimizando os ganchos de memesização da linha de montagem de fechamento (UseMememo, Usecallback, React.memo) são sobre gerenciar os ciclos de vida de fechamento com eficiência: Função DespensiveComponent ({itens, OnSelect}) {const [filter, setFilter] = usestate (“”); // sem memórias: novo fechamento todos os renderizados const FilledItems = items.Filter ((item) => item.name.includes (filtro)); // com memórias: o fechamento reutilizada até que as dependências mudem const FilledItems = useMememo (() => items.filter ((item) => item.name.includes (filtro)),
[items, filter]
); // impedir os renderizadores infantis, com o fechamento do manipulador de eventos de memórias const HandleSelect = usecallback ((id) => {oneselect (id);},
[onSelect]
); retornar
Fonte