Mudanças entre as edições de "React.js: Menus e alternando conteúdos"
(5 revisões intermediárias pelo mesmo usuário não estão sendo mostradas) | |||
Linha 1: | Linha 1: | ||
− | |||
Linha 32: | Linha 31: | ||
<div> | <div> | ||
<h1>Bem-vindo à Página Inicial!</h1> | <h1>Bem-vindo à Página Inicial!</h1> | ||
− | <p>Este é o conteúdo da página Home.</p> | + | <p>Este é o conteúdo da página Home do site {this.props.name}.</p> |
</div> | </div> | ||
); | ); | ||
Linha 39: | Linha 38: | ||
export default Home; | export default Home; | ||
− | </syntaxhighlight>Lembre-se, o componente pode ser uma função também, o que em alguns casos pode simplificar em termos visuais | + | </syntaxhighlight>Lembre-se, o componente pode ser uma função também, o que em alguns casos pode simplificar em termos visuais. Por exemplo, o código acima pode ser apresentado também da seguinte forma:<syntaxhighlight lang="javascript"> |
+ | import React from 'react'; | ||
+ | |||
+ | const Home = ({ name }) => ( | ||
+ | <> | ||
+ | <h1>Bem-vindo à Página Inicial!</h1> | ||
+ | <p>Este é o conteúdo da página Home do site {name}.</p> | ||
+ | </> | ||
+ | ); | ||
+ | |||
+ | export default Home; | ||
+ | </syntaxhighlight> | ||
== Conteúdo da Página Sobre == | == Conteúdo da Página Sobre == | ||
− | E teremos também o <code>About. | + | E teremos também o <code>About.jsx</code>:<syntaxhighlight lang="javascript"> |
− | import React | + | import React from 'react'; |
− | + | const About = () => ( | |
− | + | <> | |
− | + | <h1>Sobre nós</h1> | |
− | + | <p>Este é o conteúdo da página About.</p> | |
− | + | </> | |
− | + | ); | |
− | |||
− | |||
− | |||
− | |||
export default About; | export default About; | ||
+ | </syntaxhighlight>Mas veja bem, se precisarmos colocar código javascript na nossa função, então precisaremos, depois da seta, iniciar o código com chaves e no final da função fechar com chaves. E os parênteses acima deverão estar apos o return. Bem simples, na verdade, mas é que uma ''arrow function'' só retorna um bloco de coisas, e se temos código, vai mais do que apenas um bloco, então colocamos tudo em um bloco de chaves e está tudo certo. | ||
− | + | == App.jsx == | |
− | + | Por fim, temos o código do nosso <code>App.jsx</code> alterado para gerenciar o <code>Navbar</code> (menu) e os conteúdos. Veja que agora estamos usando o Bootstrap no nosso código:<syntaxhighlight lang="javascript"> | |
− | == App. | + | import { Component } from 'react'; |
− | Por fim, temos o código do nosso <code>App. | + | import 'bootstrap/dist/css/bootstrap.min.css'; |
− | import | ||
− | import '. | ||
import Home from './Home'; | import Home from './Home'; | ||
import About from './About'; | import About from './About'; | ||
Linha 70: | Linha 75: | ||
constructor(props) { | constructor(props) { | ||
super(props); | super(props); | ||
− | this.state = { | + | // Como o nome do site não precisamos alterar, então |
− | + | // não precisa ser state, apenas atributo da classe. | |
− | + | this.siteName = "Meu Site"; | |
+ | // State para gerenciar qual a página será o conteúdo. | ||
+ | this.state = { content: 'Home' }; | ||
} | } | ||
− | /* Tratamento do clique do menu para alterar o conteúdo da página. | + | /* |
− | + | Tratamento do clique do menu para alterar o conteúdo da | |
+ | página. Isso deve ser gerenciado por meio de um state. | ||
*/ | */ | ||
handleMenuClick = (page) => { | handleMenuClick = (page) => { | ||
Linha 82: | Linha 90: | ||
}; | }; | ||
− | /* Renderizador da Navbar com os ítens do menu. Veja que ao clicar, | + | /* |
− | + | Renderizador da Navbar com os ítens do menu. Veja que ao | |
+ | clicar, chamamos a função de tratamento do click do menu. | ||
+ | Veja que agora estamos usando o bootstrap. Contudo, diferente | ||
+ | do HTML normal onde usamos class="...", aqui usamos className. | ||
*/ | */ | ||
renderNavbar() { | renderNavbar() { | ||
return ( | return ( | ||
− | <nav className="navbar"> | + | <nav className="navbar navbar-expand-lg navbar-dark bg-dark"> |
− | <ul className=" | + | <div className="container-fluid"> |
− | + | <a className="navbar-brand" href="#">{this.siteName}</a> | |
− | + | <button className="navbar-toggler" type="button" | |
− | + | data-bs-toggle="collapse" data-bs-target="#navbarNav"> | |
− | + | <span className="navbar-toggler-icon"></span> | |
− | + | </button> | |
− | </ | + | <div className="collapse navbar-collapse" id="navbarNav"> |
− | </ | + | <ul className="navbar-nav"> |
+ | <li className="nav-item"> | ||
+ | <a className="nav-link" href="#" | ||
+ | onClick={() => this.handleMenuClick('Home')}>Início</a> | ||
+ | </li> | ||
+ | <li className="nav-item"> | ||
+ | <a className="nav-link" href="#" | ||
+ | onClick={() => this.handleMenuClick('About')}>Sobre</a> | ||
+ | </li> | ||
+ | </ul> | ||
+ | </div> | ||
+ | </div> | ||
</nav> | </nav> | ||
); | ); | ||
} | } | ||
− | /* Renderizamos o conteúdo por meio de um condicional if. Pegamos do state | + | /* |
− | + | Renderizamos o conteúdo por meio de um condicional if. Pegamos do state | |
+ | qual o ítem que foi clicado e então chamamos a classe específica. | ||
*/ | */ | ||
renderContent() { | renderContent() { | ||
const { content } = this.state; | const { content } = this.state; | ||
if (content === 'Home') { | if (content === 'Home') { | ||
− | return <Home />; | + | // Ao chamar Home, passamos o nome do site como parâmetro. |
+ | return <Home name={this.siteName} />; | ||
} else if (content === 'About') { | } else if (content === 'About') { | ||
return <About />; | return <About />; | ||
Linha 112: | Linha 136: | ||
} | } | ||
− | /* | + | /* |
+ | Aqui construímos nossa aplicação com a estrutura do navbar, | ||
+ | do conteúdo e do rodapé. O conteúdo será alterado conforme | ||
+ | o que selecionarmos no menu, ou navbar. | ||
+ | */ | ||
render() { | render() { | ||
return ( | return ( | ||
<div className="App"> | <div className="App"> | ||
− | |||
{this.renderNavbar()} | {this.renderNavbar()} | ||
− | + | <div className="container mt-4"> | |
− | <div className=" | ||
{this.renderContent()} | {this.renderContent()} | ||
</div> | </div> | ||
− | + | <footer className="bg-dark text-light text-center py-3 mt-5"> | |
− | <footer className=" | + | <p>© 2024 {this.siteName}. Todos os direitos reservados.</p> |
− | <p>© 2024 | ||
</footer> | </footer> | ||
</div> | </div> | ||
Linha 134: | Linha 159: | ||
export default App; | export default App; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Usando Função e useState == | ||
+ | Existem várias formas de escrevermos nosso código. Muitas vezes elas deixam o nosso código mais simples e com menos linha, apesar de não necessariamente bem organizado. | ||
+ | |||
+ | No exemplo a seguir, vamos utilizar também o recurso do <code>useState</code>. O <code>useState</code> é um <code>hook</code> fornecido pelo React para que possamos criar variáveis de estado em componentes funcionais. | ||
− | </syntaxhighlight> | + | Diferente de variáveis comuns, o estado é "reativo": quando ele muda, o React automaticamente renderiza novamente o componente, refletindo a nova informação na interface. |
+ | |||
+ | A função <code>useState</code> retorna um <code>array</code> com dois elementos: | ||
+ | |||
+ | * o valor atual do estado | ||
+ | * uma função que permite atualizar esse valor | ||
+ | |||
+ | '''Exemplo:'''<syntaxhighlight lang="javascript"> | ||
+ | const [content, setContent] = useState('Home'); | ||
+ | </syntaxhighlight> Aqui, <code>content</code> começa com o valor 'Home', e usamos 'setContent' para alterar esse valor depois. Seguimos com o código abaixo:<syntaxhighlight lang="javascript"> | ||
+ | import { useState } from 'react'; | ||
+ | import 'bootstrap/dist/css/bootstrap.min.css'; | ||
+ | import Home from './Home'; | ||
+ | import About from './About'; | ||
+ | |||
+ | const App = () => { | ||
+ | const siteName = "Meu Site"; | ||
+ | const [content, setContent] = useState('Home'); | ||
+ | |||
+ | const renderNavbar = () => ( | ||
+ | <nav className="navbar navbar-expand-lg navbar-dark bg-dark"> | ||
+ | <div className="container-fluid"> | ||
+ | <a className="navbar-brand" href="#">{siteName}</a> | ||
+ | <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"> | ||
+ | <span className="navbar-toggler-icon"></span> | ||
+ | </button> | ||
+ | <div className="collapse navbar-collapse" id="navbarNav"> | ||
+ | <ul className="navbar-nav"> | ||
+ | <li className="nav-item"> | ||
+ | <a className="nav-link" href="#" onClick={() => setContent('Home')}>Início</a> | ||
+ | </li> | ||
+ | <li className="nav-item"> | ||
+ | <a className="nav-link" href="#" onClick={() => setContent('About')}>Sobre</a> | ||
+ | </li> | ||
+ | </ul> | ||
+ | </div> | ||
+ | </div> | ||
+ | </nav> | ||
+ | ); | ||
+ | |||
+ | return ( | ||
+ | <div className="App"> | ||
+ | {renderNavbar()} | ||
+ | |||
+ | <div className="container mt-4"> | ||
+ | {/* Veja que não temos o renderContent e podemos usar um | ||
+ | tipo de condicional inline no HTML */} | ||
+ | {content === 'Home' && <Home name={siteName} />} | ||
+ | {content === 'About' && <About />} | ||
+ | </div> | ||
+ | |||
+ | <footer className="bg-dark text-light text-center py-3 mt-5"> | ||
+ | <p>© 2024 {siteName}. Todos os direitos reservados.</p> | ||
+ | </footer> | ||
+ | </div> | ||
+ | ); | ||
+ | }; | ||
+ | |||
+ | export default App; | ||
+ | |||
+ | </syntaxhighlight>Veja que agora não precisamos do método <code>handleMenuClick</code> porque o <code>setContent</code> pode ser usado no evento <code>onClick</code>, automatizando o processo e facilitando a escrita do nosso código. | ||
+ | |||
+ | Outra coisa é que ao invés de usar o <code>renderContent</code>, fazemos uma espécie de <code>if</code> ''inline'' no nosso <code>return</code>, adicionando apenas o conteúdo que fecha com o nome em <code>content</code>. | ||
+ | |||
+ | A ideia desse if inline na verdade não é um IF e pode parecer estranho, mas é mais simples do que parece. O que temos é apenas uma operação lógica. no caso: | ||
+ | 1o_TESTE AND 2o_TESTE | ||
+ | Na verdade, o que temos tem a ver com a forma como operações lógicas são avaliadas. | ||
+ | |||
+ | Quando <code>1o_TESTE</code> é avaliado, temos o resultado de <code>TRUE</code> ou <code>FALSE</code>, ou seja, VERDADEIRO ou FALSO. Como temos um AND na operação lógica, significa que os dois testes devem resultar em verdadeiro para a operação lógica total retornar VERDADE. Se um deles, no caso o primeiro, já for FALSO, então o resultado será falso independente do resultado do segundo teste. | ||
+ | |||
+ | Ok, mas o que isso tem a ver com o nosso negócio que é tipo um IF? | ||
+ | |||
+ | Então, considerando que o teste da esquerda resulte em VERDADE, é necessário testar (ou executar) o lado direito, no caso, estamos apenas chamando um componente React, e está tudo bem! Só que se o teste da esquerda retornasse FALSO, então o motor de avaliação lógica, por uma questão de economia de processamento para coisas óbvias, nem testaria (ou executaria) o lado direito. | ||
+ | |||
+ | OU SEJA, Só vamos instanciar o componente (à direita) caso a condição à esquerda for satisfeita, ou seja, ser VERDADE.<syntaxhighlight lang="javascript"> | ||
+ | {content === 'Home' && <Home name={siteName} />} | ||
+ | </syntaxhighlight>Dessa forma, podemos usar IF dentro do nosso código HTML no Babel (JSX). | ||
+ | |||
+ | Muito simples e fácil, não? |
Edição atual tal como às 13h04min de 23 de abril de 2025
Afluentes: Desenvolvimento Front-end II
Alterando o Conteúdo
O aplicativo criado com o Vite é muito legal e prático, mas o que é criado é apenas o motor do que vamos querer trabalhar, então pode não ser muito bom esteticamente quando estamos lidando com a identidade visual de uma empresa, organização ou mesmo gosto pessoal. Então, o que vamos fazer aqui é excluir, ou comentar os arquivos CSS usados pelo nosso aplicativo.
No arquivo src/main.jsx
, exclua ou comente a linha abaixo
import './index.css'
Podemos criar um CSS customizado na nossa página ou usar um pronto. Basta adicioná-lo com import. Veja que podemos apenas alterar o conteúdo de index.css
sem problemas.
Contudo, no nosso caso, vamos usar o Bootstrap para vite no nosso aplicativo.
Primeiro, dentro da pasta raiz do nosso projeto já criado, vamos instalar o Bootstrap da seguinte forma:
npm install bootstrap
E agora podemos adicionar no nosso arquivo do aplicativo, src/App.js
o import:
import 'bootstrap/dist/css/bootstrap.min.css';
Pronto! Nossa aplicação agora vai trabalhar com o visual do Bootstrap e sem o CSS básico que vem com o vite, que no nosso caso não ia ficar legal.
Conteúdo da Página Inicial
Agora vamos criar um arquivo JSX
para o conteúdo da página inicial. Então, dentro de src
crie o arquivo Home.jsx
com o seguinte conteúdo:
import React, { Component } from 'react';
class Home extends Component {
render() {
return (
<div>
<h1>Bem-vindo à Página Inicial!</h1>
<p>Este é o conteúdo da página Home do site {this.props.name}.</p>
</div>
);
}
}
export default Home;
Lembre-se, o componente pode ser uma função também, o que em alguns casos pode simplificar em termos visuais. Por exemplo, o código acima pode ser apresentado também da seguinte forma:
import React from 'react';
const Home = ({ name }) => (
<>
<h1>Bem-vindo à Página Inicial!</h1>
<p>Este é o conteúdo da página Home do site {name}.</p>
</>
);
export default Home;
Conteúdo da Página Sobre
E teremos também o About.jsx
:
import React from 'react';
const About = () => (
<>
<h1>Sobre nós</h1>
<p>Este é o conteúdo da página About.</p>
</>
);
export default About;
Mas veja bem, se precisarmos colocar código javascript na nossa função, então precisaremos, depois da seta, iniciar o código com chaves e no final da função fechar com chaves. E os parênteses acima deverão estar apos o return. Bem simples, na verdade, mas é que uma arrow function só retorna um bloco de coisas, e se temos código, vai mais do que apenas um bloco, então colocamos tudo em um bloco de chaves e está tudo certo.
App.jsx
Por fim, temos o código do nosso App.jsx
alterado para gerenciar o Navbar
(menu) e os conteúdos. Veja que agora estamos usando o Bootstrap no nosso código:
import { Component } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Home from './Home';
import About from './About';
class App extends Component {
constructor(props) {
super(props);
// Como o nome do site não precisamos alterar, então
// não precisa ser state, apenas atributo da classe.
this.siteName = "Meu Site";
// State para gerenciar qual a página será o conteúdo.
this.state = { content: 'Home' };
}
/*
Tratamento do clique do menu para alterar o conteúdo da
página. Isso deve ser gerenciado por meio de um state.
*/
handleMenuClick = (page) => {
this.setState({ content: page });
};
/*
Renderizador da Navbar com os ítens do menu. Veja que ao
clicar, chamamos a função de tratamento do click do menu.
Veja que agora estamos usando o bootstrap. Contudo, diferente
do HTML normal onde usamos class="...", aqui usamos className.
*/
renderNavbar() {
return (
<nav className="navbar navbar-expand-lg navbar-dark bg-dark">
<div className="container-fluid">
<a className="navbar-brand" href="#">{this.siteName}</a>
<button className="navbar-toggler" type="button"
data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav">
<li className="nav-item">
<a className="nav-link" href="#"
onClick={() => this.handleMenuClick('Home')}>Início</a>
</li>
<li className="nav-item">
<a className="nav-link" href="#"
onClick={() => this.handleMenuClick('About')}>Sobre</a>
</li>
</ul>
</div>
</div>
</nav>
);
}
/*
Renderizamos o conteúdo por meio de um condicional if. Pegamos do state
qual o ítem que foi clicado e então chamamos a classe específica.
*/
renderContent() {
const { content } = this.state;
if (content === 'Home') {
// Ao chamar Home, passamos o nome do site como parâmetro.
return <Home name={this.siteName} />;
} else if (content === 'About') {
return <About />;
}
}
/*
Aqui construímos nossa aplicação com a estrutura do navbar,
do conteúdo e do rodapé. O conteúdo será alterado conforme
o que selecionarmos no menu, ou navbar.
*/
render() {
return (
<div className="App">
{this.renderNavbar()}
<div className="container mt-4">
{this.renderContent()}
</div>
<footer className="bg-dark text-light text-center py-3 mt-5">
<p>© 2024 {this.siteName}. Todos os direitos reservados.</p>
</footer>
</div>
);
}
}
export default App;
Usando Função e useState
Existem várias formas de escrevermos nosso código. Muitas vezes elas deixam o nosso código mais simples e com menos linha, apesar de não necessariamente bem organizado.
No exemplo a seguir, vamos utilizar também o recurso do useState
. O useState
é um hook
fornecido pelo React para que possamos criar variáveis de estado em componentes funcionais.
Diferente de variáveis comuns, o estado é "reativo": quando ele muda, o React automaticamente renderiza novamente o componente, refletindo a nova informação na interface.
A função useState
retorna um array
com dois elementos:
- o valor atual do estado
- uma função que permite atualizar esse valor
Exemplo:
const [content, setContent] = useState('Home');
Aqui, content
começa com o valor 'Home', e usamos 'setContent' para alterar esse valor depois. Seguimos com o código abaixo:
import { useState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Home from './Home';
import About from './About';
const App = () => {
const siteName = "Meu Site";
const [content, setContent] = useState('Home');
const renderNavbar = () => (
<nav className="navbar navbar-expand-lg navbar-dark bg-dark">
<div className="container-fluid">
<a className="navbar-brand" href="#">{siteName}</a>
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav">
<li className="nav-item">
<a className="nav-link" href="#" onClick={() => setContent('Home')}>Início</a>
</li>
<li className="nav-item">
<a className="nav-link" href="#" onClick={() => setContent('About')}>Sobre</a>
</li>
</ul>
</div>
</div>
</nav>
);
return (
<div className="App">
{renderNavbar()}
<div className="container mt-4">
{/* Veja que não temos o renderContent e podemos usar um
tipo de condicional inline no HTML */}
{content === 'Home' && <Home name={siteName} />}
{content === 'About' && <About />}
</div>
<footer className="bg-dark text-light text-center py-3 mt-5">
<p>© 2024 {siteName}. Todos os direitos reservados.</p>
</footer>
</div>
);
};
export default App;
Veja que agora não precisamos do método handleMenuClick
porque o setContent
pode ser usado no evento onClick
, automatizando o processo e facilitando a escrita do nosso código.
Outra coisa é que ao invés de usar o renderContent
, fazemos uma espécie de if
inline no nosso return
, adicionando apenas o conteúdo que fecha com o nome em content
.
A ideia desse if inline na verdade não é um IF e pode parecer estranho, mas é mais simples do que parece. O que temos é apenas uma operação lógica. no caso:
1o_TESTE AND 2o_TESTE
Na verdade, o que temos tem a ver com a forma como operações lógicas são avaliadas.
Quando 1o_TESTE
é avaliado, temos o resultado de TRUE
ou FALSE
, ou seja, VERDADEIRO ou FALSO. Como temos um AND na operação lógica, significa que os dois testes devem resultar em verdadeiro para a operação lógica total retornar VERDADE. Se um deles, no caso o primeiro, já for FALSO, então o resultado será falso independente do resultado do segundo teste.
Ok, mas o que isso tem a ver com o nosso negócio que é tipo um IF?
Então, considerando que o teste da esquerda resulte em VERDADE, é necessário testar (ou executar) o lado direito, no caso, estamos apenas chamando um componente React, e está tudo bem! Só que se o teste da esquerda retornasse FALSO, então o motor de avaliação lógica, por uma questão de economia de processamento para coisas óbvias, nem testaria (ou executaria) o lado direito.
OU SEJA, Só vamos instanciar o componente (à direita) caso a condição à esquerda for satisfeita, ou seja, ser VERDADE.
{content === 'Home' && <Home name={siteName} />}
Dessa forma, podemos usar IF dentro do nosso código HTML no Babel (JSX).
Muito simples e fácil, não?