├── 00-start ├── src │ ├── api │ │ ├── index.ts │ │ └── github.api.ts │ ├── styles.css │ ├── pages │ │ ├── index.ts │ │ ├── components │ │ │ ├── index.ts │ │ │ ├── list.component.tsx │ │ │ └── detail.component.tsx │ │ ├── organization.tsx │ │ └── login.tsx │ ├── index.tsx │ ├── index.html │ └── app.tsx ├── .babelrc ├── tsconfig.json ├── package.json ├── webpack.config.js └── readme_es.md ├── 01-implemented ├── src │ ├── api │ │ ├── index.ts │ │ └── github.api.ts │ ├── styles.css │ ├── pages │ │ ├── index.ts │ │ ├── components │ │ │ ├── index.ts │ │ │ ├── list.component.tsx │ │ │ └── detail.component.tsx │ │ ├── organization.tsx │ │ └── login.tsx │ ├── index.tsx │ ├── index.html │ └── app.tsx ├── .babelrc ├── tsconfig.json ├── readme_es.md ├── package.json └── webpack.config.js ├── .gitignore ├── README.md └── LICENSE /00-start/src/api/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./github.api"; 2 | -------------------------------------------------------------------------------- /01-implemented/src/api/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./github.api"; 2 | -------------------------------------------------------------------------------- /00-start/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | package-lock.json 4 | .cache 5 | .awcache -------------------------------------------------------------------------------- /01-implemented/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | } 4 | -------------------------------------------------------------------------------- /00-start/src/pages/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./login"; 2 | export * from "./organization"; 3 | -------------------------------------------------------------------------------- /01-implemented/src/pages/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./login"; 2 | export * from "./organization"; 3 | -------------------------------------------------------------------------------- /00-start/src/pages/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./list.component"; 2 | export * from "./detail.component"; 3 | -------------------------------------------------------------------------------- /01-implemented/src/pages/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./list.component"; 2 | export * from "./detail.component"; 3 | -------------------------------------------------------------------------------- /00-start/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/preset-typescript", 5 | "@babel/preset-react" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /01-implemented/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/preset-typescript", 5 | "@babel/preset-react" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /00-start/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import { App } from "./app"; 4 | 5 | ReactDOM.render( 6 |
7 | 8 |
, 9 | document.getElementById("root") 10 | ); 11 | -------------------------------------------------------------------------------- /01-implemented/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import { App } from "./app"; 4 | 5 | ReactDOM.render( 6 |
7 | 8 |
, 9 | document.getElementById("root") 10 | ); 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # example-nested-routes-ts 2 | 3 | Demo del video tutorial 4 | [React Router V6 - Nested Routes](https://www.lemoncode.tv/curso/react-router-v6/leccion/nested-routes) 5 | 6 | Cómo funcionan las nested routes en 7 | React Router Version 6. 8 | 9 | -------------------------------------------------------------------------------- /00-start/src/pages/organization.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { ListComponent, DetailComponent } from "./components"; 3 | 4 | export const OrganizationPage: React.FC = () => { 5 | return ( 6 | <> 7 |

Hello from Organization page

8 | 9 | 10 | 11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /00-start/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | My App Example 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /01-implemented/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | My App Example 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /01-implemented/src/pages/organization.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Outlet } from "react-router-dom"; 3 | import { ListComponent, DetailComponent } from "./components"; 4 | 5 | export const OrganizationPage: React.FC = () => { 6 | return ( 7 | <> 8 |

Hello from Organization page

9 | 10 | 11 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /00-start/src/pages/login.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link, useNavigate } from "react-router-dom"; 3 | 4 | export const LoginPage: React.FC = () => { 5 | const navigate = useNavigate(); 6 | 7 | const handleNavigation = () => { 8 | navigate("/organization"); 9 | }; 10 | 11 | return ( 12 | <> 13 |

Hello from login page

14 | 15 | 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /00-start/src/app.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; 3 | import { LoginPage, OrganizationPage } from "./pages"; 4 | 5 | export const App = () => { 6 | return ( 7 | 8 | 9 | } /> 10 | } /> 11 | 12 | 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /01-implemented/src/pages/login.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link, useNavigate } from "react-router-dom"; 3 | 4 | export const LoginPage: React.FC = () => { 5 | const navigate = useNavigate(); 6 | 7 | const handleNavigation = () => { 8 | navigate("/organization"); 9 | }; 10 | 11 | return ( 12 | <> 13 |

Hello from login page

14 | 15 | 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /00-start/src/api/github.api.ts: -------------------------------------------------------------------------------- 1 | export const getOrganizationMemberCollection = ( 2 | organization: string 3 | ): Promise => 4 | fetch(`https://api.github.com/orgs/${organization}/members`) 5 | .then((response) => response.json()) 6 | .then((json) => json); 7 | 8 | export const getMemberDetail = (memberLogin: string): Promise => 9 | fetch(`https://api.github.com/users/${memberLogin}`) 10 | .then((response) => response.json()) 11 | .then((json) => json); 12 | -------------------------------------------------------------------------------- /01-implemented/src/api/github.api.ts: -------------------------------------------------------------------------------- 1 | export const getOrganizationMemberCollection = ( 2 | organization: string 3 | ): Promise => 4 | fetch(`https://api.github.com/orgs/${organization}/members`) 5 | .then((response) => response.json()) 6 | .then((json) => json); 7 | 8 | export const getMemberDetail = (memberLogin: string): Promise => 9 | fetch(`https://api.github.com/users/${memberLogin}`) 10 | .then((response) => response.json()) 11 | .then((json) => json); 12 | -------------------------------------------------------------------------------- /00-start/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "es6", 5 | "moduleResolution": "node", 6 | "declaration": false, 7 | "noImplicitAny": false, 8 | "allowSyntheticDefaultImports": true, 9 | "sourceMap": true, 10 | "jsx": "react", 11 | "noLib": false, 12 | "suppressImplicitAnyIndexErrors": true, 13 | "skipLibCheck": true, 14 | "esModuleInterop": true 15 | }, 16 | "include": ["src/**/*"], 17 | "exclude": ["node_modules"] 18 | } 19 | -------------------------------------------------------------------------------- /01-implemented/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "es6", 5 | "moduleResolution": "node", 6 | "declaration": false, 7 | "noImplicitAny": false, 8 | "allowSyntheticDefaultImports": true, 9 | "sourceMap": true, 10 | "jsx": "react", 11 | "noLib": false, 12 | "suppressImplicitAnyIndexErrors": true, 13 | "skipLibCheck": true, 14 | "esModuleInterop": true 15 | }, 16 | "include": ["src/**/*"], 17 | "exclude": ["node_modules"] 18 | } 19 | -------------------------------------------------------------------------------- /01-implemented/src/app.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; 3 | import { LoginPage, OrganizationPage } from "./pages"; 4 | import { DetailComponent, ListComponent } from "./pages/components"; 5 | 6 | export const App = () => { 7 | return ( 8 | 9 | 10 | } /> 11 | }> 12 | } /> 13 | 14 | 15 | 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /00-start/src/pages/components/list.component.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { getOrganizationMemberCollection } from "../../api"; 3 | 4 | export const ListComponent = () => { 5 | const [memberCollection, setMemberCollection] = React.useState([]); 6 | 7 | React.useEffect(() => { 8 | getOrganizationMemberCollection("lemoncode").then((memberCollection) => { 9 | setMemberCollection(memberCollection); 10 | }); 11 | }, []); 12 | 13 | return ( 14 | <> 15 |
    16 | {memberCollection.map((member) => ( 17 |
  • {member.login}
  • 18 | ))} 19 |
20 | 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /01-implemented/src/pages/components/list.component.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link, generatePath } from "react-router-dom"; 3 | import { getOrganizationMemberCollection } from "../../api"; 4 | 5 | export const ListComponent = () => { 6 | const [memberCollection, setMemberCollection] = React.useState([]); 7 | 8 | React.useEffect(() => { 9 | getOrganizationMemberCollection("lemoncode").then((memberCollection) => { 10 | setMemberCollection(memberCollection); 11 | }); 12 | }, []); 13 | 14 | return ( 15 | <> 16 |
    17 | {memberCollection.map((member) => ( 18 |
  • 19 | 24 | {member.login} 25 | 26 |
  • 27 | ))} 28 |
29 | 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /00-start/src/pages/components/detail.component.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { getMemberDetail } from "../../api"; 3 | 4 | interface MemberDetailEntity { 5 | id: string; 6 | login: string; 7 | name: string; 8 | company: string; 9 | bio: string; 10 | } 11 | 12 | const createDefaultMemberDetail = () => ({ 13 | id: "", 14 | login: "", 15 | name: "", 16 | company: "", 17 | bio: "", 18 | }); 19 | 20 | export const DetailComponent = () => { 21 | const [member, setMember] = React.useState( 22 | createDefaultMemberDetail() 23 | ); 24 | 25 | React.useEffect(() => { 26 | getMemberDetail("brauliodiez").then((memberCollection) => { 27 | setMember(memberCollection); 28 | }); 29 | }, []); 30 | 31 | return ( 32 | <> 33 |

Hello from Detail page

34 |

id: {member.id}

35 |

login: {member.login}

36 |

name: {member.name}

37 |

company: {member.company}

38 |

bio: {member.bio}

39 | 40 | ); 41 | }; 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Lemoncode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /01-implemented/src/pages/components/detail.component.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useParams } from "react-router-dom"; 3 | import { getMemberDetail } from "../../api"; 4 | 5 | interface MemberDetailEntity { 6 | id: string; 7 | login: string; 8 | name: string; 9 | company: string; 10 | bio: string; 11 | } 12 | 13 | const createDefaultMemberDetail = () => ({ 14 | id: "", 15 | login: "", 16 | name: "", 17 | company: "", 18 | bio: "", 19 | }); 20 | 21 | export const DetailComponent = () => { 22 | const { loginSlug } = useParams(); 23 | 24 | const [member, setMember] = React.useState( 25 | createDefaultMemberDetail() 26 | ); 27 | 28 | React.useEffect(() => { 29 | if (loginSlug) { 30 | getMemberDetail(loginSlug).then((memberCollection) => { 31 | setMember(memberCollection); 32 | }); 33 | } 34 | }, [loginSlug]); 35 | 36 | return ( 37 | <> 38 |

Hello from Detail page

39 |

id: {member.id}

40 |

login: {member.login}

41 |

name: {member.name}

42 |

company: {member.company}

43 |

bio: {member.bio}

44 | 45 | ); 46 | }; 47 | -------------------------------------------------------------------------------- /01-implemented/readme_es.md: -------------------------------------------------------------------------------- 1 | # 01 implemented 2 | 3 | Vamos a implementar el siguiente escenario: 4 | 5 | - Muestro una lista de enlaces con los nombres de los miembros de una organización. 6 | - Cuando el usuario pincha en uno de los enlaces se muestra la informacíon del 7 | miembro que se ha pinchado sin cambiar de página (usando rutas anidadas) 8 | 9 | En la carpeta _01-implemented_ puedes encontrar el ejemplo completo, y un readme con el 10 | paso a paso, también puedes ver un vídeo de como funciona esto en Lemoncode Tv: 11 | 12 | # Pasos 13 | 14 | Puedes encontrar un vídeo explicativo así como un post con la guía para implementar 15 | el ejemplo en el siguiente enlace: 16 | 17 | # ¿Te apuntas a nuestro máster? 18 | 19 | Si te ha gustado este ejemplo y tienes ganas de aprender Front End 20 | guiado por un grupo de profesionales ¿Por qué no te apuntas a 21 | nuestro [Máster Front End Online Lemoncode](https://lemoncode.net/master-frontend#inicio-banner)? Tenemos tanto edición de convocatoria 22 | con clases en vivo, como edición continua con mentorización, para 23 | que puedas ir a tu ritmo y aprender mucho. 24 | 25 | Y si tienes ganas de meterte una zambullida en el mundo _devops_ 26 | apuntate nuestro [Bootcamp devops online Lemoncode](https://lemoncode.net/bootcamp-devops#bootcamp-devops/inicio) 27 | -------------------------------------------------------------------------------- /00-start/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "run-p -l type-check:watch start:dev", 8 | "type-check": "tsc --noEmit", 9 | "type-check:watch": "npm run type-check -- --watch", 10 | "start:dev": "webpack-dev-server --mode development --open", 11 | "build": "rimraf dist && webpack --mode development" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "@babel/cli": "^7.15.7", 17 | "@babel/core": "^7.15.8", 18 | "@babel/preset-env": "^7.15.8", 19 | "@babel/preset-react": "^7.14.5", 20 | "@babel/preset-typescript": "^7.15.0", 21 | "@types/react": "^17.0.32", 22 | "@types/react-dom": "^17.0.10", 23 | "babel-loader": "^8.2.3", 24 | "css-loader": "^6.4.0", 25 | "file-loader": "^6.2.0", 26 | "html-loader": "^3.0.0", 27 | "html-webpack-plugin": "^5.4.0", 28 | "npm-run-all": "^4.1.5", 29 | "rimraf": "^3.0.2", 30 | "style-loader": "^3.3.1", 31 | "typescript": "^4.4.4", 32 | "url-loader": "^4.1.1", 33 | "webpack": "^5.59.1", 34 | "webpack-cli": "^4.9.1", 35 | "webpack-dev-server": "^4.3.1" 36 | }, 37 | "dependencies": { 38 | "react": "^17.0.2", 39 | "react-dom": "^17.0.2", 40 | "react-router-dom": "^6.0.2" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /01-implemented/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "run-p -l type-check:watch start:dev", 8 | "type-check": "tsc --noEmit", 9 | "type-check:watch": "npm run type-check -- --watch", 10 | "start:dev": "webpack-dev-server --mode development --open", 11 | "build": "rimraf dist && webpack --mode development" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "@babel/cli": "^7.15.7", 17 | "@babel/core": "^7.15.8", 18 | "@babel/preset-env": "^7.15.8", 19 | "@babel/preset-react": "^7.14.5", 20 | "@babel/preset-typescript": "^7.15.0", 21 | "@types/react": "^17.0.32", 22 | "@types/react-dom": "^17.0.10", 23 | "babel-loader": "^8.2.3", 24 | "css-loader": "^6.4.0", 25 | "file-loader": "^6.2.0", 26 | "html-loader": "^3.0.0", 27 | "html-webpack-plugin": "^5.4.0", 28 | "npm-run-all": "^4.1.5", 29 | "rimraf": "^3.0.2", 30 | "style-loader": "^3.3.1", 31 | "typescript": "^4.4.4", 32 | "url-loader": "^4.1.1", 33 | "webpack": "^5.59.1", 34 | "webpack-cli": "^4.9.1", 35 | "webpack-dev-server": "^4.3.1" 36 | }, 37 | "dependencies": { 38 | "react": "^17.0.2", 39 | "react-dom": "^17.0.2", 40 | "react-router-dom": "^6.0.2" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /00-start/webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 2 | const path = require("path"); 3 | const basePath = __dirname; 4 | 5 | module.exports = { 6 | context: path.join(basePath, "src"), 7 | resolve: { 8 | extensions: [".js", ".ts", ".tsx"], 9 | }, 10 | entry: { 11 | app: ["./index.tsx", "./styles.css"], 12 | }, 13 | devtool: "eval-source-map", 14 | stats: "errors-only", 15 | output: { 16 | filename: "[name].[chunkhash].js", 17 | publicPath: "/", 18 | }, 19 | devServer: { 20 | historyApiFallback: true, 21 | }, 22 | module: { 23 | rules: [ 24 | { 25 | test: /\.tsx?$/, 26 | exclude: /node_modules/, 27 | loader: "babel-loader", 28 | }, 29 | { 30 | test: /\.(png|jpg)$/, 31 | exclude: /node_modules/, 32 | loader: "url-loader", 33 | }, 34 | { 35 | test: /\.html$/, 36 | loader: "html-loader", 37 | }, 38 | { 39 | test: /\.css$/, 40 | exclude: /node_modules/, 41 | use: [ 42 | { 43 | loader: "style-loader", 44 | }, 45 | { 46 | loader: "css-loader", 47 | }, 48 | ], 49 | }, 50 | ], 51 | }, 52 | plugins: [ 53 | //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin 54 | new HtmlWebpackPlugin({ 55 | filename: "index.html", //Name of file in ./dist/ 56 | template: "index.html", //Name of template in ./src 57 | }), 58 | ], 59 | }; 60 | -------------------------------------------------------------------------------- /01-implemented/webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 2 | const path = require("path"); 3 | const basePath = __dirname; 4 | 5 | module.exports = { 6 | context: path.join(basePath, "src"), 7 | resolve: { 8 | extensions: [".js", ".ts", ".tsx"], 9 | }, 10 | entry: { 11 | app: ["./index.tsx", "./styles.css"], 12 | }, 13 | devtool: "eval-source-map", 14 | stats: "errors-only", 15 | output: { 16 | filename: "[name].[chunkhash].js", 17 | publicPath: "/", 18 | }, 19 | devServer: { 20 | historyApiFallback: true, 21 | }, 22 | module: { 23 | rules: [ 24 | { 25 | test: /\.tsx?$/, 26 | exclude: /node_modules/, 27 | loader: "babel-loader", 28 | }, 29 | { 30 | test: /\.(png|jpg)$/, 31 | exclude: /node_modules/, 32 | loader: "url-loader", 33 | }, 34 | { 35 | test: /\.html$/, 36 | loader: "html-loader", 37 | }, 38 | { 39 | test: /\.css$/, 40 | exclude: /node_modules/, 41 | use: [ 42 | { 43 | loader: "style-loader", 44 | }, 45 | { 46 | loader: "css-loader", 47 | }, 48 | ], 49 | }, 50 | ], 51 | }, 52 | plugins: [ 53 | //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin 54 | new HtmlWebpackPlugin({ 55 | filename: "index.html", //Name of file in ./dist/ 56 | template: "index.html", //Name of template in ./src 57 | }), 58 | ], 59 | }; 60 | -------------------------------------------------------------------------------- /00-start/readme_es.md: -------------------------------------------------------------------------------- 1 | # 00 start 2 | 3 | En este ejemplo tenemos: 4 | 5 | - Una aplicación que corre con React y TypeScript. 6 | - React Router V 6 7 | - Dos rutas una de login y otra de vista de organización. 8 | - En la vista de orgnización mostramos: 9 | - Los miembros que pertenece a Lemoncode. 10 | - La ficha de perfil de un miembro en concreto (este miembro está harcodeado) 11 | 12 | ¿Qué queremos hacer? 13 | 14 | Utilizar las nested Routes de React Router 6 para mostrar un maestro/detalle en la 15 | página de orgnización: 16 | 17 | - Muestro una lista de enlaces con los nombres de los miembros de una organización. 18 | - Cuando el usuario pincha en uno de los enlaces se muestra la informacíon del 19 | miembro que se ha pinchado sin cambiar de página (usando rutas anidadas) 20 | 21 | En la carpeta _01-implemented_ puedes encontrar el ejemplo completo, y un readme con el 22 | paso a paso, también puedes ver un vídeo de como funciona esto en Lemoncode Tv: 23 | 24 | # ¿Te apuntas a nuestro máster? 25 | 26 | Si te ha gustado este ejemplo y tienes ganas de aprender Front End 27 | guiado por un grupo de profesionales ¿Por qué no te apuntas a 28 | nuestro [Máster Front End Online Lemoncode](https://lemoncode.net/master-frontend#inicio-banner)? Tenemos tanto edición de convocatoria 29 | con clases en vivo, como edición continua con mentorización, para 30 | que puedas ir a tu ritmo y aprender mucho. 31 | 32 | Y si tienes ganas de meterte una zambullida en el mundo _devops_ 33 | apuntate nuestro [Bootcamp devops online Lemoncode](https://lemoncode.net/bootcamp-devops#bootcamp-devops/inicio) 34 | --------------------------------------------------------------------------------