A maioria das pessoas que trabalha no frontend, de uma forma ou de outra, se deparou com uma reação. Esta é uma biblioteca JavaScript que ajuda a criar interfaces interessantes; nos últimos anos, ganhou enorme popularidade. No entanto, muitas pessoas não sabem como funciona por dentro.
Nesta série de artigos, lemos o código e tentamos descobrir por que os pacotes que estão ocultos pela reação são responsáveis, para que são usados e como funcionam. Os mais básicos que usamos no navegador são react
, react-dom
, events
e react-reconciler
.
Vamos avançar e hoje temos um artigo sobre o pacote react
. Quem se importa com o que está neste pacote - vá para baixo do gato
Primeiramente, faremos um pequeno exemplo, com base no qual consideraremos este pacote. Nosso gadget ficará assim:
function App() { const [text, changeText] = React.useState('Initial'); return ( <div className="app"> <span>{text}</span> <input type="text" value={text} onInput={(e) => changeText(e.target.value)} /> </div> ); } ReactDOM.render( <App />, document.getElementById('root') ) ;
Vamos dar uma rápida olhada neste pedaço de código. Aqui vemos a chamada do gancho através de React.useState('Initial')
, um pouco de JSX e a chamada do método render para obter tudo isso na página.
De fato, como muitas pessoas sabem, esse não é o código final que o navegador processa. Antes de ser executado, é transpilado, por exemplo, com um babel. Nesse caso, o que a função retorna se tornará o seguinte:
return React.createElement( "div", { className: "app" }, React.createElement("span", null, text), React.createElement("input", { type: "text", value: text, onInput: function onInput(e) { return changeText(e.target.value); } }) );
Quem se importa em experimentar e ver em que seu código babel se transforma - babel repl .
React.createElement
Então, recebemos muitas chamadas para React.createElement()
e tempo para ver o que essa função faz. Vamos descrevê-lo em palavras (ou você também pode consultar o arquivo - ReactElement.js ).
Primeiro de tudo, ele verifica se temos props (no código, o objeto com props que passamos é chamado config
).
Em seguida, verificamos se temos key
e ref
que não estão undefined
e as salvamos, se houver.
if (hasValidKey(config)) { key = '' + config.key; }
Um ponto interessante é que config.key
é config.key
em uma string, o que significa que você pode passar qualquer tipo de dado como chave, o principal é que implementa o .toString()
ou .valueOf()
e retorna um valor exclusivo para um conjunto específico.
A seguir estão as seguintes etapas:
- copie os objetos que foram passados para o elemento;
- adicione o campo
children
lá se passá-los não com adereços, mas como um elemento aninhado; - definimos valores padrão de
defaultProps
para as propriedades que não definimos anteriormente.
Quando preparamos todos os dados, chamamos uma função interna que cria um objeto que descreve nosso componente. Este objeto fica assim:
{ // This tag allows us to uniquely identify this as a React Element $$typeof: REACT_ELEMENT_TYPE, // Symbol // Built-in properties that belong on the element type: type, key: key, ref: ref, props: props, // Record the component responsible for creating this element. _owner: owner, }
Aqui temos a propriedade $$typeof
, que é um símbolo, portanto, deslize de qualquer maneira qual objeto falhará.
A propriedade type
armazena o tipo do elemento a ser criado. No caso do nosso exemplo, essa será a função App()
e as linhas 'div'
, 'span'
e 'input'
.
A propriedade key
conterá a mesma chave, por causa da qual os warings voam para o console.
Props conterão o que passamos, children
e o que foi especificado em defaultProps
. A propriedade _owner
necessária para o trabalho correto com ref
.
Traduzido para o nosso exemplo, o resultado de React.createElement(App, null)
aparência:
{ $$typeof: REACT_ELEMENT_TYPE, type: App, key: null, ref: null, props: {}, _owner: null, }
Além disso, no modo dev, teremos um campo adicional que será usado para exibir uma bela pilha com o nome e a linha do arquivo:
_source: { fileName: "/Users/appleseed/react-example/src/index.js", lineNumber: 7 }

Para resumir um pouco do que vimos acima. O pacote react
atua como um tradutor entre nós e o restante dos pacotes que trabalham mais em nosso aplicativo, traduzindo nossas chamadas em palavras que são compreensíveis, por exemplo, para o reconciliador.
React.useState
Na versão 16.8, apareciam ganchos. O que é e como usá-lo, você pode ler o link , mas agora vamos dar uma olhada no que está no pacote react
.
De fato, não há muito a dizer. Em essência, um pacote é uma fachada através da qual nossos desafios vão para entidades internas.
Portanto, useState
nada mais é do que duas linhas de código:
export function useState<S>(initialState: (() => S) | S) { const dispatcher = resolveDispatcher(); return dispatcher.useState(initialState); }
Os ganchos restantes parecem quase idênticos. Aqui temos o despachante atual, que é um objeto e contém campos, por exemplo, useState
. Esse expedidor muda dependendo se temos a primeira renderização agora ou apenas queremos atualizar o componente.
A implementação real dos ganchos é armazenada no pacote react-reconciler
, sobre o qual falaremos em um dos seguintes artigos.
O que vem a seguir
Mais uma coisa. Depois de ler este artigo, você pode entender por que sempre importamos o pacote react, mesmo que não o usemos diretamente. Isso é necessário para que, após digerir nosso jsx pela bolha, tenhamos uma variável React
.
Os caras da equipe de reação cuidaram disso (e não apenas isso) e agora estão trabalhando para substituir o createElement
.
Tentando explicar em poucas palavras: existe um desejo de substituir o método atual de criação de elementos por dois - jsx
e jsxs
. Isso é necessário por vários motivos:
- discutimos acima como o
createElement
funciona. Ele constantemente copia adereços e adiciona o campo children
ao objeto, no qual salva os filhos que passamos como argumentos para a função (3 argumentos e mais). Agora, propõe-se fazer isso no estágio de conversão de chamadas jsx
para javascript
, porque criar um elemento é uma função frequentemente chamada e não é livre para executar modificações de adereços no tempo de execução a cada vez; - você pode se livrar de importar o objeto
React
e importar apenas funções específicas ( import { jsx } from 'react'
, por exemplo) e, consequentemente, conseguir não adicionar ao assembly o que não estamos usando. Além disso, você não precisa resolver o campo createElement
do objeto React
todas as vezes, porque também não é gratuito; - Discutimos acima que temos um caso especial quando puxamos a
key
dos adereços e a encaminhamos ainda mais. Agora, propõe-se pegar a key
de jsx
no estágio de transpilação e passar o terceiro parâmetro para a função de criação do elemento.
Leia mais aqui . O pacote jsx
já possui os jsxs
e jsxs
. Se você quiser brincar com isso, pode clonar o repositório enableJSXTransformAPI
, defina o sinalizador enableJSXTransformAPI
como true
no arquivo ReactFeatureFlags.js
do pacote shared
e compile sua versão do ReactFeatureFlags.js
( yarn build
) com a nova API ativada.
Final
Terminarei com isso a história de hoje sobre o pacote react
e da próxima vez falaremos sobre como o pacote react-dom
usa o que o react
cria e quais métodos e como ele é implementado.
Obrigado por ler até o fim!