Criando sites reativos com JavaScript puro

Vinícius Campitelli

Sobre

Sobre

Sobre mim

Vinícius Campitelli
Vinícius
Campitelli
  • Bacharel em Ciência da Computação pela UFSCar
  • Desenvolvedor há 20 anos
  • Membro do PHPSP
  • Entusiasta em cibersegurança
  • Consultor de TI e instrutor de treinamentos

Sobre

Slides

Acesse os slides remotamente em:

QR Code
viniciuscampitelli.com/slides-sites-reativos-javascript

Sobre

Repositório

Acesse os slides e os códigos das demonstrações localmente clonando o repositório:


                            $ git clone --recursive git@github.com:vcampitelli/slides-sites-reativos-javascript.git
                        
github.com/vcampitelli/slides-sites-reativos-javascript

Disclaimer

Disclaimer

A ideia dessa palestra é despertar a curiosidade! Em cenários reais, utilize bibliotecas robustas, como React, Svelte, Vue.js ou Angular.
Também existem outras alternativas, como SolidJS, Preact (compatível com React) ou até mesmo htmx.

Uma breve história do tempo...

Uma breve história do tempo...

Os (meus) primórdios com PHP


                            <html>
                                <body>
                                    <div id="header">
                                        <!-- ... -->
                                        <a href="/pagina">Link</a>
                                    </div>
                                    <iframe src="body.php?page=<?= $_GET['page'] ?>" name="centro"></iframe>
                                    <div id="footer">
                                        <!-- ... -->
                                    </div>
                                </body>
                            </html>
                        

Uma breve história do tempo...

Revolução com jQuery (2006 ~ 2013)

Além de Dojo, Backbone, MooTools, a primeira versão do AngularJS...


                            $(document).ready(function() {
                                $.ajax({
                                  url: '/posts/1',
                                  method: 'GET',
                                  success: function (post) {
                                    $('#loading').fadeOut();
                                    $('#content')
                                        .html('

' + post.title + '

' + post.body + '

') .fadeIn(); }, error: function() { $('#loading').fadeOut(); $('#content').html('Erro ao carregar os dados').fadeIn(); } }); });
A Complete History of JavaScript Frameworks in the Modern Age, from the Perspective of a Confused Backend Developer

Uma breve história do tempo...

Novo mundo com React e Vue (2013...)

Exemplo de código em React


                                    export default function MyApp() {
                                      return (
                                        <div>
                                          <h1>Bem-vindo ao meu aplicativo</h1>
                                          <Componente />
                                        </div>
                                      );
                                    }
                                

Exemplo de código em Vue


                                    <div id="app">
                                      <button @click="count++">
                                        Count is: {{ count }}
                                      </button>
                                    </div>
                                
[JSConfUS 2013] Tom Occhino and Jordan Walke: JS Apps at Facebook

Conceitos

Conceitos

JSX

JSX is a syntax extension for JavaScript that lets you write HTML-like markup inside a JavaScript file.
Documentação do React

Conceitos

JSX

Código em JSX


                                    import { useState } from 'react';

                                    export default function Componente() {
                                        const [count, setCount] = useState(0);

                                        return (
                                            <div>
                                                <p>Você clicou {count} vezes</p>

                                                <button
                                                    type="button"
                                                    onClick={() => setCount(count + 1)}>
                                                    Incrementar
                                                </button>
                                            </div>
                                        );
                                    }
                                

Código transpilado em JavaScript


                                    import { useState } from 'react';

                                    export default function Componente () {
                                        const [count, setCount] = useState(0);
                                        return React.createElement(
                                            'div', null,
                                            React.createElement(
                                                'p', null,
                                                'Voc\xEA clicou ', count, ' vezes'
                                            ),
                                            React.createElement(
                                                'button',
                                                {
                                                    type: 'button',
                                                    onClick: () => setCount(count + 1),
                                                },
                                                'Incrementar',
                                            )
                                        );
                                    }
                                

Conceitos

Virtual DOM

O virtual DOM (VDOM) é um conceito de programação onde uma representação ideal, ou “virtual”, da interface do usuário é mantida em memória e sincronizada com o DOM “real” por uma biblioteca como o ReactDOM.
Documentação do React

Conceitos

Hooks

São recursos que permitem que você gerencie o estado, ciclos de vida do componente e outros recursos do React sem precisar escrever componentes em forma de classes.
Blog da Trybe

Vamos ver alguns problemas...
e suas soluções!

Problema

Interpolar expressões, estruturas condicionais e de repetição são difíceis


                                    const $ul = document.createElement('ul');
                                    for (const item of items) {
                                        const $li = document.createElement('li');
                                        $li.id = `item-${item.id}`;
                                        $li.innerText = item.nome;
                                        $ul.appendChild($li);
                                    }

                                    document.body.appendChild($ul);
                                
Solução no React

Criação do JSX para facilitar o manuseio de elementos


                                    return (
                                        <ul>
                                            {itens.map((item) => (
                                                <li id={`item-${item.id}`}>
                                                    {item.nome}
                                                </li>
                                            )}
                                        </ul>
                                    );
                                
Problema

Recarregar componentes quando algum valor é alterado ou precisa ser recomputado


                                    <div>
                                        <p>
                                            Você clicou <span id="count">0</span> vezes
                                        </p>
                                        <button type="button" id="btn-click">
                                            Incrementar
                                        </button>
                                    </div>
                                

                                    let count = 0;
                                    const $count = document.getElementById('count');
                                    const $button = document.getElementById('btn-click');
                                    $button.onclick = function () {
                                        $count.innerText = ++count;
                                    };
                                
Solução no React

Funcionalidade useState() que retorna um array com dois elementos: o valor atual e um método de mutação


                                    import { useState } from 'react';

                                    export default function Componente() {
                                        const [count, setCount] = useState(0);

                                        return (
                                            <div>
                                                <p>Você clicou {count} vezes</p>
                                                <button
                                                    type="button"
                                                    onClick={() => setCount(count + 1)}>
                                                    Incrementar
                                                </button>
                                            </div>
                                        );
                                    }
                                
Problema

Fluxo para exibir um texto "Carregando" enquanto realiza uma operação assíncrona


                                    <div id="loading">Carregando...<div>
                                    <div id="body" style="display: none"><div>
                                

                                    const $body = document.getElementById('body');

                                    fetch('/posts')
                                        .then(r => r.json())
                                        .then((data) => {
                                            $body.innerText = `${data.id} ${data.name}`;

                                            $loading.style.display = 'none';
                                            $body.style.display = 'block';
                                        });
                                
Solução no React

Hook useEffect() que executa uma função ao carregar o componente pela primeira vez


                                    import { useEffect, useState } from 'react';

                                    export default function Componente() {
                                        const [data, setData] = useState(null);
                                        useEffect(() => {
                                            fetch('/posts')
                                                .then(r => r.json())
                                                .then(setData);
                                        }, []);

                                        if (data === null) {
                                            return (
                                                <div>Carregando...</div>
                                            );
                                        }

                                        return (
                                            <div>{data.id} {data.name}</div>
                                        );
                                    }
                                
Problema

Executar uma função sempre que determinados valores forem alterados


                                    <select>
                                        <!-- Options... -->
                                    <select>
                                    <div id="loading">Carregando...<div>
                                    <div id="body" style="display: none"><div>
                                

                                    const $loading = document.getElementById('loading');
                                    const $select = document.getElementById('select');
                                    const $body = document.getElementById('body');

                                    $select.onchange = function (e) {
                                        const postId = e.target.value;

                                        $loading.style.display = 'block';

                                        fetch(`/posts/${postId}`)
                                            .then(r => r.json())
                                            .then((post) => {
                                                $body.innerText = post.contents;
                                            })
                                            .finally(() => {
                                                $loading.style.display = 'none';
                                            });
                                    };
                                
Solução no React

Hook useEffect() com um array de dependências para executar a função


                                    import { useEffect, useState } from 'react';

                                    export default function Componente() {
                                        const [postId, setPostId] = useState(null);
                                        const [data, setData] = useState(null);

                                        useEffect(() => {
                                            if (!postId) return;

                                            setData(null);
                                            fetch(`/posts/${id}`)
                                                .then(r => r.json())
                                                .then(setData);
                                        }, [postId]);

                                        const $select = (
                                            <select onChange={(e) => {
                                                setPostId(e.target.value);
                                            }}>
                                                {/* Options... */}
                                            <select>
                                        );

                                        if (data === null) {
                                            return (
                                                <>
                                                    {$select}
                                                    <div>Carregando...</div>
                                                </>
                                            );
                                        }

                                        return (
                                            <>
                                                {$select}
                                                <div>{data.contents}</div>
                                            </>
                                        );
                                    }
                                
Problema
Passar informações entre componentes da página

                                    import { getCurrentTheme } from '@/preferences';

                                    document.body.classList.add(
                                        getCurrentTheme()
                                    );
                                

                                    import { setCurrentTheme } from '@/preferences';

                                    setCurrentTheme('dark');

                                    document.location.reload(true);

                                    // ou algo como:

                                    reloadTheme();
                                
Solução no React

Hooks createContext e useContext para criação e uso de informações


                                    import { createContext } from 'react';

                                    export const ThemeContext = createContext(null);

                                    export default function Theme() {
                                        return (
                                            <ThemeContext.Provider value="light">
                                                <App />
                                            </ThemeContext.Provider>
                                        );
                                    }
                                

                                    import { useContext } from 'react';
                                    import ThemeContext from '@/providers/ThemeContext';

                                    export default function App() {
                                        const theme = useContext(ThemeContext);

                                        return (
                                            <body className={theme}>
                                                {/* ... */}
                                            </body>
                                        );
                                    }
                                
Problema

                                
Solução no React

                                

Referências

Referências

Treinamentos in company

Workshops
Gostou? Então conheça meus treinamentos corporativos e sob demanda sobre Desenvolvimento, Segurança da Informação, DevOps, Arquitetura de Sistemas e diversos outros assuntos em viniciuscampitelli.com

Obrigado!