Estou tentando usar o sider do menu AntD como um painel de guias.
Desejo colocar componentes dentro do conteúdo para que o painel de conteúdo renderize o componente relacionado quando um item de menu for clicado.
Como faço para que essa estrutura aceite componentes como o conteúdo de cada item de menu?
import React from 'react';
import { compose } from 'recompose';
import { Divider, Layout, Card, Tabs, Typography, Menu, Breadcrumb, Icon } from 'antd';
import { PasswordForgetForm } from '../Auth/Password/Forgot';
const { Title } = Typography
const { TabPane } = Tabs;
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;
class Dashboard extends React.Component {
state = {
collapsed: false,
};
onCollapse = collapsed => {
console.log(collapsed);
this.setState({ collapsed });
};
render() {
return (
<Layout style={{ minHeight: '100vh' }}>
<Sider collapsible collapsed={this.state.collapsed} onCollapse={this.onCollapse}>
<div />
<Menu theme="light" defaultSelectedKeys={['1']} mode="inline" >
<Menu.Item key="1">
<Icon type="fire" />
<span>Next item</span>
<PasswordForgetForm />
</Menu.Item>
<Menu.Item key="2">
<Icon type="fire" />
<span>Next item</span>
<Another component to render in the content div />
</Menu.Item>
</Menu>
</Sider>
<Layout>
<Header style={{ background: '#fff', padding: 0 }} />
<Content style={{ margin: '0 16px', background: '#fff' }}>
<div style={{ padding: 24, background: '#fff', minHeight: 360 }}>
RENDER RELEVANT COMPONENT HERE BASED ON MENU ITEM SELECTED
</div>
</Content>
</Layout>
</Layout>
);
}
}
export default Dashboard;
Quando tento renderizar isso, nenhum erro é gerado, mas a div do conteúdo não é atualizada com o PasswordForgetForm que eu especifiquei como o conteúdo do item de menu.
No entanto, tentei a sugestão de Chris - que funciona bem para renderizar o componente para cada um dos diferentes itens de menu divs no segmento de layout - a desvantagem dessa abordagem é que, a cada atualização de página, o caminho vai para o componente de conteúdo para esse item de menu específico, em vez da página de teste que contém o menu - e o componente de conteúdo com esse conteúdo relevante. Se essa abordagem for aprovada como sensata, existe uma maneira de manter a página atualizada na página original, em vez de tentar acessar um URL de item de menu de subconjunto?
Atualizar
Eu encontrei essa literatura . Eu acho que isso pode ser o que eu preciso saber, mas a linguagem é técnica demais para eu entender. Alguém pode ajudar com uma versão em inglês simples deste assunto?
Eu também encontrei este tutorial que usa o Pose para ajudar na renderização. Embora essa estrutura seja o que estou tentando alcançar, parece que o Pose foi preterido. Alguém sabe se é necessário ir além do react-router para obter este resultado, ou existe uma solução no react que eu possa implementar?
Este exemplo é semelhante ao que eu quero, mas não consigo encontrar nada que defina a barra lateral (que parece ser um argumento necessário para fazer isso funcionar).
Eu também vi este post . Embora algumas das respostas sejam uma cópia e pasta dos documentos, pergunto-me se a resposta de Adam Gering está mais próxima do que eu preciso. Estou tentando manter o menu Sider na rota / dash o tempo todo. Esse URL não deve mudar - independentemente de qual item de menu no sider o usuário clica, mas a div de conteúdo no componente / dash deve ser atualizada para renderizar o componente no caminho de rota especificado.
APLICANDO A SUGESTÃO DE CHRIS
Chris gentilmente ofereceu uma sugestão abaixo. Eu tentei, mas a circunstância em que ele não funciona como desejado é quando o item de menu é clicado (e o componente relevante é carregado corretamente na divisão de conteúdo, mas se eu atualizar a página, a atualização tentará carregar uma página com um URL que é para o componente que deveria estar dentro da div de conteúdo na página do painel.
import React from 'react';
import {
BrowserRouter as Router,
Route,
Link,
Switch,
} from 'react-router-dom';
import * as ROUTES from '../../constants/Routes';
import { compose } from 'recompose';
import { Divider, Layout, Card, Tabs, Typography, Menu, Breadcrumb, Icon } from 'antd';
import { withFirebase } from '../Firebase/Index';
import { AuthUserContext, withAuthorization, withEmailVerification } from '../Session/Index';
// import UserName from '../Users/UserName';
import Account from '../Account/Index';
import Test from '../Test/Index';
const { Title } = Typography
const { TabPane } = Tabs;
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;
class Dashboard extends React.Component {
state = {
collapsed: false,
};
onCollapse = collapsed => {
console.log(collapsed);
this.setState({ collapsed });
};
render() {
const { loading } = this.state;
// const dbUser = this.props.firebase.app.snapshot.data();
// const user = Firebase.auth().currentUser;
return (
<AuthUserContext.Consumer>
{authUser => (
<div>
{authUser.email}
<Router>
<Layout style={{ minHeight: '100vh' }}>
<Sider collapsible collapsed={this.state.collapsed} onCollapse={this.onCollapse}>
<div />
<Menu theme="light" defaultSelectedKeys={['1']} mode="inline" >
<SubMenu
key="sub1"
title={
<span>
<Icon type="user" />
<span>Profile</span>
</span>
}
>
<Menu.Item key="2"><Link to={ROUTES.ACCOUNT}>Account Settings</Link></Menu.Item>
<Menu.Item key="3"><Link to={ROUTES.TEST}>2nd content component</Link></Menu.Item>
</SubMenu>
</Menu>
</Sider>
<Layout>
<Header> </Header>
<Content style={{ margin: '0 16px', background: '#fff' }}>
<div style={{ padding: 24, background: '#fff', minHeight: 360 }}>
<Switch>
<Route path={ROUTES.ACCOUNT}>
<Account />
</Route>
<Route path={ROUTES.TEST}>
< Test />
</Route>
</Switch>
</div>
</Content>
<Footer style={{ textAlign: 'center' }}>
test footer
</Footer>
</Layout>
</Layout>
</Router>
</div>
)}
</AuthUserContext.Consumer>
);
}
}
export default Dashboard;
No meu arquivo de rotas, tenho:
export const ACCOUNT = '/account';
Eu também encontrei este tutorial - que usa a mesma abordagem descrita acima - e não é redirecionado da mesma maneira que meu código é atualizado na página. O tutorial usa Route em vez de BrowserRouter - mas, caso contrário, não vejo diferenças.
PRÓXIMA TENTATIVA
Vi este post (obrigado Matt). Eu tentei seguir as sugestões nesse post.
Eu removi o invólucro do roteador externo da página Painel (existe um roteador em torno do App.js, que é onde a rota para o Painel é configurada).
Em seguida, no meu Painel, alterei a div Conteúdo para:
Eu adicionei:
let match = useRouteMatch();
para o método render dentro do meu componente Dashboard (como mostrado aqui ).
Adicionei useRouteMatch à minha declaração de importação do react-router-dom.
Isso produz um erro que diz:
Erro: chamada inválida. Ganchos só podem ser chamados dentro do corpo de um componente de função. Isso pode acontecer por um dos seguintes motivos: 1. Você pode ter versões incompatíveis do React e do renderizador (como React DOM) 2. Você pode estar violando as Regras dos Ganchos
Há mais mensagens no erro acima, mas o estouro de pilha não me permite publicá-lo porque possui um link curto
Não sei o que fiz de errado nessas etapas, mas se eu comentar a instrução let, a página será carregada.
Quando vou a / Dashboard e clico em "account", espero que o componente da conta seja renderizado dentro da div de conteúdo que tenho no layout da página Dashboard. Em vez disso, ele redireciona diretamente para uma página em localhost3000 / account (para a qual não há referência de página - é apenas um componente para renderizar dentro da página Painel).
Portanto, isso é pior do que o problema com o qual comecei - porque, pelo menos no início, o redirecionamento aconteceu apenas na atualização da página. Agora isso acontece imediatamente.
Encontrei este repositório com exemplos de cada tipo de rota. Não consigo ver o que está fazendo e não estou.
Este post parece ter tido o mesmo problema que eu e o resolveu usando a mesma abordagem que eu tentei. É uma publicação de 2018, para que a passagem do tempo torne a abordagem desatualizada - mas não vejo diferença entre o que essa solução de publicação implementa e minha tentativa original.
PRÓXIMA TENTATIVA
Eu pensei que tinha encontrado uma abordagem que funcione na resposta de Lyubomir neste post .
Eu tenho:
<Menu.Item key="2">
<Link to=
{ ${this.props.match.url}/account
}> Configurações da conta
Em seguida, na div no componente traço onde quero exibir esse componente, tenho:
<div>
<Switch>
<Route exact path={`${this.props.match.url}/:account`} component={Account} />
Isso funciona. Na atualização da página, posso manter as coisas funcionando como deveriam.
NO ENTANTO, quando adiciono um segundo item de menu com:
<Menu.Item key="16">
<Link to={`${this.props.match.url}/learn`}>
<Icon type="solution" />
<span>Lern</span>
</Link>
</Menu.Item>
Em vez de renderizar o componente Aprendizado quando o item de menu para / aprender é clicado (e a barra de URL muda para aprender), o componente Conta é renderizado. Se eu excluir a exibição da conta do extrato do switch, posso exibir o componente de aprendizado correto.
Com essa tentativa, tenho os itens de menu trabalhando para corresponder a uma extensão de URL do painel (por exemplo, localhost / dash / account ou localhost / dash / learn) apenas para UM item de menu. Se eu adicionar um segundo item de menu, a única maneira de processar corretamente o segundo componente é excluindo o primeiro item de menu. Estou usando o switch com caminhos exatos.
Quero que esta solução funcione com vários itens de menu.
Eu tentei o caminho alternativo para o URL (por exemplo:
<Link to={`${this.props.match.url}/learn`}>
é o mesmo que:
<Link to={`${this.props.match.path}/learn`}>
Eu li a explicação neste blog e, embora não compreenda completamente essas opções. Eu li isso . Ele sugere que a instrução match agora é um método herdado para renderizar componentes (agora que os ganchos estão disponíveis). Não consigo encontrar nenhum material de treinamento que mostre como usar ganchos para alcançar o resultado esperado.
PasswordForgottenForm
componente também.