You don't have access to this class

Keep learning! Join and start boosting your career

Aprovecha el precio especial y haz tu profesión a prueba de IA

Antes: $249

Currency
$209
Suscríbete

Termina en:

0 Días
9 Hrs
5 Min
50 Seg

Cambiando modales por navegación

22/30
Resources

How to simplify the navigation process in a React application by eliminating portals?

Managing routes and navigation in React applications can become a challenge if an efficient approach is not used. Historically, this could include additional dependencies such as portals and modals, but as the instructor describes, there is a trend in the industry to simplify the design by using routes instead of portals, leveraging React Router DOM. The following steps will guide you on how to effectively replace portals with routes to improve your application's navigation.

What's involved in eliminating modals and portals?

The first step is to identify all components related to the use of portals, such as modals. In the code, you may notice instructions such as OpenModal that need to be removed. Once located, they are replaced with routes using React Router DOM's useNavigate. The navigate function is imported and configured appropriately to allow buttons to redirect to specific new routes, such as /new.

import { useNavigate } from 'react-router-dom';
const MyComponent = () => { const navigate = useNavigate();
 return ( <button onClick={() => navigate('/new')}>Create New To-Do</button> );};

How to adapt components for navigation between routes?

The next step is to modify each component that interacted with the portals to work with the new routing logic. This involves updating the properties that were received and defined in components such as ToDoForm. The properties that controlled the visibility of the modal must be replaced with events that manipulate routes.

// Before<button onClick={props.setOpenModal(!props.openModal)}></button>
// After<button onClick={props.onClick}></button>

How to integrate the create To-Dos function with navigation between paths?

The To-Dos create and edit forms are central to the application. Each is encapsulated in a new page with logic to send the entered data through props and handle related events. Here the use of navigate allows returning to home after a successful submission.

const NewToDoPage = () => { const navigate = useNavigate(); const handleAddToDo = () => { // Logic to add To-Do // Then redirect to home navigate('/'); };    
 return ( <ToDoForm  label="Write your new to-do"  submitText="Add"  onSubmit={handleAddToDo}/> );};

How to customize the components for the edit page?

Select which component properties should be adjusted dynamically, such as button texts or headers depending on whether a To-Do is being created or edited. Define properties such as label and submitText to reflect correct actions depending on the operation the user wants to perform.

const EditToDoPage = ({ allId }) => { const navigate = useNavigate(); const handleEditToDo = () => { // Logic for editing To-Do // Then redirect to home navigate('/'); };
 return ( <ToDoForm  label="Edit your To-Do"  submitText="Edit"  onSubmit={handleEditToDo}/> );};

Final tips for robust navigation in React.

  • Keep routes simple: Make sure routes are descriptive and appropriate to enhance the user experience.
  • Use reusable components: Design components that can be easily reused by adjusting only the necessary properties.
  • Functionality testing: Test every change made to the interface to ensure that navigation between components blends intuitively.

Implementing these best practices will not only help keep your code clean and efficient, but will also provide a superior user experience by simplifying navigation through paths rather than using complicated portals. Keep exploring and improving your skills, constant practice is the key to web development mastery.

Contributions 12

Questions 3

Sort by:

Want to see more contributions, questions and answers from the community?

umm, mi lado radical eliminó todo lo que tenía delineado amarillo, pero mi lado prudente hizo commit antes de eso.

¡Hola, comunidad! 👋

👀 Yo cree un div que encierre o agrupe el formulario para poder centrarlo, ya que si lo hacemos de la forma normal con el margin auto, en responsive se rompe un poco la ui

const NewPage = () => {
  return (
    <div className='new-todo-container'>
      <TodoForm
        title="Write your new TODO"
        submitText="Add"
        submitEvent={() => console.log('llamar a add todo')}
      />
    </div>
  )
}

Y el css

.new-todo-container{
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

Espero les sirva.

Saludos.

Una alternativa a la funcionalidad creada en la clase para los textos dinamicos, es usar el hook de React Router DOM ‘useLocation’ que devuelve la ruta actualmente usada y con esto hacer la validación necesaria.

Creo que así, nos evitamos el tener que mandar props adicionales.

const location = useLocation();
<label>{(location.pathname === '/new') ? 'Escribe tu TODO' : 'Edita tu TODO'}</label>

Yo el botón de CreateTodo lo cambiaría por un componente Link.
Esto dice la documentación 👇:

Además, un componente Link es una etiqueta <a href=""> por detrás, lo cual es necesario para tener un buen SEO.
.
Es el equivalente a usar un <button> en vez de un <a> para cambiar de URLs en HTML puro.

Hey, here again! 👋 I leave you my english version repo, branch and commit: **- English ver. branch** <https://github.com/SebaMat3/react-todo/tree/feat/implement-react-router-navigation> **Branch name:** feat/implement-react-router-navigation **Commit message:** git commit -m "refactor: replace modals with router navigation \- Remove Modal component usage in HomePage \- Add navigation routes for new and edit todo forms \- Implement NewTodoPage and EditTodoPage components \- Update TodoForm to use router navigation instead of modal state \- Update CreateTodoButton to use navigation \- Remove unused modal state and related code \- Add router parameters for edit todo functionality BREAKING CHANGE: This replaces the modal-based navigation with React Router"

Estaba pensando otra manera que se podría hacer es que al agregar tareas, en lugar de navegar a una página de Edit o New Todo, se añada un nuevo input al final de los todos y deshabilitar su uso modificación hasta que se haga click en Edit.

Me pasó que justo cuando hice los cambios con el profe no tenía TODOS para confirmar si lo que hice estaba bien, así que tuve que hacer por adelantado el añadir TODOS (Aunque no sé si es la mejor forma, me funcionó)

import React from "react";
import { TodoForm } from "../../ui/TodoForm";
import { useTodos } from "../useTodos";


function NewTodoPage() {
    const { stateUpdaters } = useTodos();

    const { addTodo } = stateUpdaters;
    return(
       <TodoForm 
       label="Escribe tu nuevo TO DO"
       submit="Añadir"
       submitEvent={addTodo}
       />
    )
}


export { NewTodoPage }

Hola papus, dejo el codigo de la clase en TS:

import { FC, FormEvent, useState } from "react"
import { useLocation, useNavigate } from "react-router-dom";
import './TodoForm.css'

interface Props {
    submitEvent: (v:string)=>void,
}

const TodoForm:FC<Props> = ({ submitEvent }) =>{

    const navigate = useNavigate();
    const location = useLocation();
    const [newTodoText, setNewTodoText] = useState('');

    const onCancel = ()=>{
        navigate('/');
    }

    const onSubmit = (e:FormEvent<HTMLFormElement>) => {
        e.preventDefault();
        submitEvent(newTodoText);
        navigate('/');
    }

    return(
        <form onSubmit={onSubmit}>
            <label>{location.pathname === '/new'? 'Escribe tu nueva tarea pendiente':'Edita tu tarea pendiente'}</label>
            <textarea 
                placeholder="Hola, que haremos hoy?"
                value={newTodoText}
                onChange={(event)=>{
                    setNewTodoText(event.target.value)
                }}
            />
            <div className="TodoForm-buttonContainer">
                <button
                    type="button"
                    onClick={onCancel}
                    className="TodoForm-button TodoForm-button--cancel"
                >
                    Cancelar
                </button>
                <button
                    type="submit"
                    className="TodoForm-button TodoForm-button--add"
                >
                    {location.pathname === '/new'? 'Añadir':'Editar'}
                </button>
            </div>
        </form>
    )
}

export { TodoForm }

sería bueno haber dejado el modal como para no perder la funcionalidad de los portales y hacer el edit en una nueva ventana

Cambiando modales por navegación

.
Vamos a eliminar los modales y portales de la aplicación para utilizar rutas en su lugar.
.
En el componente HomePage comentamos todo lo relacionado a modales y portales, importamos useNavigate y guardamos su llamado en una constante navigate.
.
Al renderizar los todos en la render prop onEdit usamos la navegación para dirigirnos a /edit/:id donde id será el ID del TODO.
.
Finalmente, el botón de crear TODOs recibirá una función flecha que por medio de navegación nos dirige a /new.
.

...
import { useNavigate } from 'react-router-dom';
...

function HomePage() {
  const navigate = useNavigate();
  ...

  const {
    ...
    // openModal,
    ...
  } = state;

  const {
    // setOpenModal,
    // addTodo,
    ...
  } = stateUpdaters;
  
  return (
    ...
        {todo => (
          <TodoItem
            key={todo.id}
            text={todo.text}
            completed={todo.completed}
            onEdit={() => navigate('/edit/' + todo.id)}
            onComplete={() => completeTodo(todo.id)}
            onDelete={() => deleteTodo(todo.id)}
          />
        )}
    ...

      {/* {!!openModal && (
        <Modal>
          <TodoForm
            addTodo={addTodo}
            setOpenModal={setOpenModal}
          />
        </Modal>
      )} */}

      <CreateTodoButton
        onClick={() => navigate('/new')}
        // setOpenModal={setOpenModal}
      />

      ...
  );
}

export { HomePage };

.
En el componente CreateTodoButton ya no necesitamos modales, por lo que solo le enviamos la función que pasamos por props a la propiedad onClick.
.

import React from 'react';
import './CreateTodoButton.css';

function CreateTodoButton(props) {
  return (
    <button
      className="CreateTodoButton"
      onClick={props.onClick}
    >
      +
    </button>
  );
}

export { CreateTodoButton };

.
En el componente TodoForm necesitamos que sea dinámico, tanto para editar, como para crear TODOs.
.
Lo que cambia es que ahora utilizamos navegación tanto para el botón de Cancelar como para el botón para realizar el Submit, vamos redirigir hacia /. Además nuestra función onSubmit va a utilizar una función que pasaremos por props submitEvent que será versátil para crear o editar TODOs según sea el caso.
.
Finalmente, tanto el label como el texto del botón de submit van a ser dinámicos y los pasaremos por props.
.

...
import { useNavigate } from 'react-router-dom';
...

function TodoForm(props) {
  const navigate = useNavigate();
  ...
  
  const onCancel = () => {
    navigate('/');
  };
  const onSubmit = (event) => {
    event.preventDefault();
    navigate('/');
    props.submitEvent(newTodoValue);
  };

  return (
    <form onSubmit={onSubmit}>
      <label>{props.label}</label>
      <textarea
        value={newTodoValue}
        onChange={onChange}
        placeholder="Cortar la cebolla oara el almuerzo"
      />
      <div className="TodoForm-buttonContainer">
        <button
          type="button"
          className="TodoForm-button TodoForm-button--cancel"
          onClick={onCancel}
          >
          Cancelar
        </button>
        <button
          type="submit"
          className="TodoForm-button TodoForm-button--add"
        >
          {props.submitText}
        </button>
      </div>
    </form>
  );
}

export { TodoForm };

.
Desde el archivo TodoForm.css centramos el componente y le quitamos el color de fondo que tenía en la clase form.
.

form {
  width: 90%;
  max-width: 300px;
  /* background-color: #fff; */
  margin: 0 auto;
  padding: 33px 40px;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

.
Por último, solo que modificar los componentes de EditTodoPage y NewTodoPage de la siguiente manera.
.

import React from 'react';
import { TodoForm } from '../../ui/TodoForm';

function EditTodoPage() {
  return (
    <TodoForm
      label="Edita tu TODO"
      submitText="Editar"
      submitEvent={() => console.log('Llamar a editTodo')}
    />
  );
}

export { EditTodoPage };
import React from 'react';
import { TodoForm } from '../../ui/TodoForm';

function NewTodoPage() {
  return (
    <TodoForm
      label="Escribe tu nuevo TODO"
      submitText="Añadir"
      submitEvent={() => console.log('Llamar a addTodo')}
    />
  );
}

export { NewTodoPage };
Tengo una duda existencial con los portales ¿Vale la pena tener portales cuando se usan microfrontends? Porque entiendo el porque se usan acá y el porque se remueven pero me causa curiosidad como entre un router + portales bajo esa arquitectura o ¿En ese caso no se usan?
Quise presentar mi TodoForm ya que lo hice bastante diferente a como lo hizo el profesor, y es que ya desde el principio yo estaba llamando directamente nuestro custom hook desde este componente por lo que la accion addTodo no tenia que llamarla a traves de props y ademas de eso solo recibo por props el todoId a editar, si lo paso en 0 pues es porque no es para editar si no para crear uno nuevo y ya con ese solo parametro dentro de la prop ya puedo manejar todo lo otro ```js import React from 'react'; import './TodoForm.css'; import { TodoContext } from '../TodoContext'; import { useNavigate } from 'react-router-dom'; function TodoForm({ todoId }) { const isEditMode = todoId !== 0; const navigate = useNavigate(); const { addTodo, editTodo, } = React.useContext(TodoContext); return ( <form onSubmit={(event) => { event.preventDefault(); if(!isEditMode) { addTodo(document.getElementById('TodoValue').value); document.getElementById('TodoValue').value = ''; } else { editTodo(todoId, document.getElementById('TodoValue').value); document.getElementById('TodoValue').value = ''; } navigate("/"); }}>

{!isEditMode ? "Escribe tu nuevo TODO" : "Edita tu TODO"}

<textarea placeholder='Escribe aquí tu nuevo TODO' id='TodoValue'></textarea>
<button onClick={() => navigate("/")} className='TodoFormButton TodoFormCancelButton'>Cancelar</button> <button className='TodoFormButton TodoFormCreateButton'>{!isEditMode ? "Crear" : "Editar"}</button>
</form> ); } export { TodoForm }; ```