Estoy tratando de usar el menú lateral AntD como un panel de pestañas.
Quiero poner componentes dentro del contenido para que el panel de contenido represente el componente relacionado cuando se hace clic en un elemento del menú.
¿Cómo consigo que esta estructura tome componentes como contenido para cada elemento del menú?
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;
Cuando intento representar esto, no se generan errores, pero el div de contenido no se actualiza con PasswordForgetForm que especifiqué como contenido para el elemento del menú.
Intenté la sugerencia de Chris a continuación, que funciona bien para representar el componente para cada uno de los diferentes divs de contenido de elementos de menú en el segmento de diseño, sin embargo, la desventaja de este enfoque es que con cada actualización de página, la ruta va al componente de contenido para ese elemento de menú en particular, en lugar de la página de prueba que tiene el menú, y el componente de contenido con ese contenido relevante. Si se aprueba este enfoque como razonable, ¿hay alguna manera de mantener la página actualizada en la página original, en lugar de tratar de ir a una url de elemento de menú de subconjunto?
Actualizar
Encontré esta literatura . Creo que esto podría ser lo que necesito saber, pero el lenguaje es demasiado técnico para que lo entienda. ¿Alguien puede ayudar con una versión sencilla en inglés de este tema?
También encontré este tutorial que usa Pose para ayudar con el renderizado. Si bien esta estructura es lo que estoy tratando de lograr, parece que Pose ha quedado en desuso. ¿Alguien sabe si es necesario ir más allá de reaccionar enrutador para obtener este resultado, o hay una solución dentro de reaccionar que pueda buscar implementar?
Este ejemplo es similar a lo que quiero, pero no puedo encontrar nada que defina la barra lateral (que parece ser un argumento necesario para que esto funcione).
También he visto esta publicación . Si bien algunas de las respuestas son copiar y pegar los documentos, me pregunto si la respuesta de Adam Gering está más cerca de lo que necesito. Estoy tratando de mantener el menú Sider en la ruta / dash en todo momento. Esa URL no debería cambiar, independientemente de qué elemento del menú en el lado en el que el usuario haga clic, PERO el contenido div en el componente / guión debe actualizarse para representar el componente en la ruta de ruta que he especificado.
APLICANDO LA SUGERENCIA DE CHRIS
Chris ha ofrecido amablemente una sugerencia a continuación. Lo intenté, pero la circunstancia en la que no funciona como se desea es cuando se hace clic en el elemento del menú (y el componente relevante se carga correctamente en el div de contenido, pero si actualizo la página, la actualización intenta cargar una página con un url que es para el componente que se supone que está dentro del contenido div en la página del tablero.
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;
En mi archivo de rutas, tengo:
export const ACCOUNT = '/account';
También encontré este tutorial , que utiliza el mismo enfoque descrito anteriormente, y no se redirige de la misma manera que mi código lo hace al actualizar la página. El tutorial usa Route en lugar de BrowserRouter, pero de lo contrario no puedo ver ninguna diferencia.
PRÓXIMO INTENTO
Vi esta publicación (gracias Matt). He tratado de seguir las sugerencias en esa publicación.
Eliminé el contenedor externo del Enrutador de la página del Tablero (hay un Enrutador alrededor de App.js, que es donde está configurada la ruta al Tablero).
Luego, en mi Tablero, cambié la división de Contenido a:
Yo añadí:
let match = useRouteMatch();
al método de representación dentro de mi componente Panel de instrumentos (como se muestra aquí ).
Agregué useRouteMatch a mi declaración de importación de react-router-dom.
Esto produce un error que dice:
Error: llamada de enlace no válida. Los ganchos solo se pueden llamar dentro del cuerpo de un componente de función. Esto podría suceder por una de las siguientes razones: 1. Es posible que tenga versiones que no coinciden de React y el renderizador (como React DOM) 2. Puede estar rompiendo las Reglas de Hooks
Hay más mensajes en el error anterior, pero el desbordamiento de la pila no me permite publicarlo porque tiene un enlace corto
No sé qué he hecho mal en estos pasos, pero si comento la declaración let, la página se carga.
Cuando voy a / Tablero y hago clic en "cuenta", espero que el componente de la cuenta se procese dentro del contenido div que tengo en el diseño de la página Panel. En su lugar, redirige directamente a una página en localhost3000 / account (para la cual no hay referencia de página, es solo un componente para representar dentro de la página del Panel).
Entonces, esto es peor que el problema con el que comencé, porque al menos al principio, la redirección solo ocurrió al actualizar la página. Ahora sucede de inmediato.
Encontré este repositorio que tiene ejemplos de cada tipo de ruta. No puedo ver lo que está haciendo que no soy.
Esta publicación parece haber tenido el mismo problema que yo, y la resolvió usando el mismo enfoque que he probado. Es una publicación de 2018, por lo que el paso del tiempo hace que el enfoque sea anticuado, pero no puedo ver ninguna diferencia entre lo que implementa esa solución de publicación y mi intento original.
PRÓXIMO INTENTO
Pensé que había encontrado un enfoque que funciona en la respuesta de Lyubomir en esta publicación .
Yo tengo:
<Menu.Item key="2">
<Link to=
{ ${this.props.match.url}/account
}> Configuración de la cuenta
Luego, en el div en el componente del guión donde quiero mostrar este componente, tengo:
<div>
<Switch>
<Route exact path={`${this.props.match.url}/:account`} component={Account} />
Esto funciona. En la actualización de la página, puedo mantener las cosas funcionando como deberían.
SIN EMBARGO, cuando agrego un segundo elemento de menú con:
<Menu.Item key="16">
<Link to={`${this.props.match.url}/learn`}>
<Icon type="solution" />
<span>Lern</span>
</Link>
</Menu.Item>
En lugar de representar el componente de aprendizaje cuando se hace clic en el elemento de menú para / learn (y la barra de URL cambia para aprender), se representa el componente de cuenta. Si elimino la visualización de la cuenta de la declaración de cambio, entonces puedo mostrar el componente de aprendizaje correcto.
Con este intento, tengo los elementos del menú funcionando para que coincidan con una extensión de URL del Tablero (es decir, localhost / dash / account o localhost / dash / learn) solo para UN elemento del menú. Si agrego un segundo elemento del menú, la única forma en que puedo representar correctamente el segundo componente es eliminando el primer elemento del menú. Estoy usando el interruptor con rutas exactas.
Quiero que esta solución funcione con múltiples elementos de menú.
He intentado alternar ruta para url (por ejemplo:
<Link to={`${this.props.match.url}/learn`}>
es lo mismo que:
<Link to={`${this.props.match.path}/learn`}>
He leído la explicación en este blog y aunque no entiendo completamente estas opciones. He leido esto . Sugiere que la declaración de coincidencia ahora es un método heredado para representar componentes (ahora que los ganchos están disponibles). No puedo encontrar ningún material de capacitación que muestre cómo usar ganchos para lograr el resultado esperado.
PasswordForgottenForm
componente.Respuestas:
La mejor solución es usar React Router
<Link>
para hacer que cada elemento del menú se vincule a una ruta específica, y luego en el contenido,<Switch>
para representar el componente correspondiente. Aquí está el documento: React routerRenderizar con React Router
Renderizar con teclas de menú
App.js
Sider.js
fuente
Encontré la respuesta de Lyubomir en esta publicación. Funciona. Rutas anidadas con react router v4 / v5
El enlace del elemento del menú es:
La ruta de visualización es:
Hay dos puntos antes del nombre del componente. No estoy seguro de por qué. Si alguien sabe cómo se llama este enfoque, agradecería una referencia para poder tratar de entenderlo.
fuente
:
es unparams
comodín. Entonces/app/account
es lo mismo que/app/sdfsfjfdjfjfdnfjnsdfjn
, que es lo mismo/app/doefmd
y así sucesivamente. Simplemente asigna la cadena a una variable de parámetros declarada; vea el ejemplo aquí: reacttraining.com/react-router/web/example/url-params , que declara la cadena como parámetros:id
). Si desea utilizar parámetros, deberá utilizar la ruta Regex (para múltiples parámetros) o hacer que sus rutas sean más únicas en/app/dashboard
comparación con/app/settings/5e0b97003e95542de2d8e3a1
, donde5e0b97003e95542de2d8e3a1
hay parámetros únicosid
./app/:id
coincidiría con la misma ruta que/app/:account
, que coincidiría con la misma ruta que/app/settings
. Debido al comodín param, no son lo suficientemente únicos como para enfrentarse.