Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

476
Views
En React Router v6, cómo verificar que el formulario esté sucio antes de salir de la página/ruta

A continuación se muestran las versiones del paquete que estoy usando.

 React version - 16.13.1 react-router-dom version - 6.0.0-beta.0 react-redux version 7.2.0 Material UI version 4.11.0

¿Cómo/cuál es la mejor manera de comprobar que un formulario isDirty (ha cambiado) cuando el usuario intenta salir de la página actual? Me gustaría preguntar "¿Está seguro de que desea irse..." si el formulario isDirty .

Obtendré los datos desde useEffect() y usaré un reductor de redux para representar la interfaz de usuario.

¿Debo declarar una variable para mantener los datos obtenidos originales para la verificación sucia?

Esto es lo que estoy haciendo, pero no funciona correctamente.

componente.js

 useEffect(() => { props.fetchUserInfo(); })

acción.js

 export function fetchUserInfo() { return (dispatch) => { dispatch({type: USER_INITIALSTATE, {Name: 'abc', Age: 20}} ) } }

usuarioReductor.js

 const initialState = { processing: false, success: false, fail: false, Profile: {} } let oriState; let State; const UserReducer = (state = initialState, action) => { if (action.type === USER_INITIALSTATE) { oriState = {Profile: action.data}; State = {...state, Profile: action.data}; return {...state, Profile: action.data}; } else if (action.type === OTHERS_ACTION) { //update field change return {...state, xxx} } } export const userIsDirty = state => { if (oriState && State) { return JSON.stringify(oriState.Profile) !== JSON.stringify(State.Profile); } return false; }; export default UserReducer;

Entonces, en mi componente, llamo a userIsDirty para devolver el booleano isDirty, pero no he descubierto cómo capturar el evento de página de salida y usar esto como un disparador para hacer la verificación del formulario sucio.

Entonces, ¿cómo detectar salir de la página actual? Intenté algo en useEffect return(componente umount), pero los accesorios no obtienen el estado INITIALSTATE actualizado (lo que significa que obtendré Profile: {}), porque solo se ejecuta una vez, pero si agrego el argumento de matriz opcional useEffect, obtengo un bucle infinito (¿tal vez lo configuré mal?).

 useEffect(() => { props.fetchUserInfo(); return () => { console.log(props); //not getting initial state object }; }, []);

¿Estoy haciendo esto de la manera correcta? ¿Qué me he perdido? ¿Hay una solución mejor/correcta para lograr lo que quiero?

Actualizado

Gracias @gdh, useBlocker es el que quiero. Lo estoy usando para abrir un cuadro de diálogo de confirmación.

Compartiré mis códigos y caja completos, creo que esto puede ser útil para alguien en el futuro.

mostrar el diálogo de confirmación usando useBlocker

over 4 years ago · Santiago Trujillo
6 answers
Answer question

0

Los ganchos que @gdh mencionó en su respuesta fueron eliminados por el equipo de desarrolladores de react-router. Por eso, no puede usar usePrompt o useBlocker con la versión actual de react-router (v6).

Pero el equipo mencionó que están trabajando intensamente en las funciones. referencia

Si alguien quiere implementar los cambios que hizo el equipo de remixes para ofrecer las funcionalidades de los ganchos, puede echar un vistazo a esta respuesta de github. aquí

over 4 years ago · Santiago Trujillo Report

0

Me enfrentaba a la misma situación de intentar utilizar un cuadro de diálogo de confirmación de IU "agradable" personalizado que se integraba con el gancho useBlocker de react router v6 beta para bloquear las transiciones de ruta cuando el formulario de la ruta actual tiene modificaciones no guardadas. Comencé con el código de codesandbox vinculado en la sección UPDATED al final de esta pregunta. Encontré que esta implementación de enlace personalizado no funcionaba para todas mis necesidades, así que la adapté para admitir un parámetro de expresión regular opcional para definir un conjunto de rutas que no deberían bloquearse. También cabe destacar que la implementación de codesandbox devuelve un booleano de la devolución de llamada pasada a useBlocker , pero descubrí que esto no tiene ningún efecto ni utilidad, así que lo eliminé. Aquí está mi implementación completa de TypeScript de un gancho personalizado revisado:

useNavigationWarning.ts

 import { useState, useEffect, useCallback } from 'react'; import { useBlocker, useNavigate, useLocation } from 'react-router-dom'; import { Blocker } from 'history'; export function useNavigationWarning( when: boolean, exceptPathsMatching?: RegExp ) { const navigate = useNavigate(); const location = useLocation(); const [showPrompt, setShowPrompt] = useState<boolean>(false); const [lastLocation, setLastLocation] = useState<any>(null); const [confirmedNavigation, setConfirmedNavigation] = useState<boolean>( false ); const cancelNavigation = useCallback(() => { setShowPrompt(false); }, []); const handleBlockedNavigation = useCallback<Blocker>( nextLocation => { const shouldIgnorePathChange = exceptPathsMatching?.test( nextLocation.location.pathname ); if ( !(confirmedNavigation || shouldIgnorePathChange) && nextLocation.location.pathname !== location.pathname ) { setShowPrompt(true); setLastLocation(nextLocation); } else if (shouldIgnorePathChange) { // to cancel blocking based on the route we need to retry the nextLocation nextLocation.retry(); } }, [confirmedNavigation, location.pathname, exceptPathsMatching] ); const confirmNavigation = useCallback(() => { setShowPrompt(false); setConfirmedNavigation(true); }, []); useEffect(() => { if (confirmedNavigation && lastLocation?.location) { navigate(lastLocation.location.pathname); // Reset hook state setConfirmedNavigation(false); setLastLocation(null); } }, [confirmedNavigation, lastLocation, navigate]); useBlocker(handleBlockedNavigation, when); return [showPrompt, confirmNavigation, cancelNavigation] as const; }
over 4 years ago · Santiago Trujillo Report

0

@Devb, su pregunta y actualización fueron muy útiles y me ahorraron mucho tiempo. ¡Gracias! creó un HOC basado en su código. podría ser útil para alguien. accesorios en el componente envuelto:

  • setPreventNavigation: establece cuándo bloquear la navegación

  • provideLeaveHandler: establece la función que se ejecutará cuando intente cambiar una ruta y esté bloqueado para la navegación

  • confirmNavigation - continuar la navegación

  • cancelNavigation - detener la navegación

     import React, { useEffect, useState, useCallback } from 'react' import { useNavigate, useBlocker, useLocation } from 'react-router-dom' export default function withPreventNavigation(WrappedComponent) { return function preventNavigation(props) { const navigate = useNavigate() const location = useLocation() const [lastLocation, setLastLocation] = useState(null) const [confirmedNavigation, setConfirmedNavigation] = useState(false) const [shouldBlock, setShouldBlock] = useState(false) let handleLeave = null const cancelNavigation = useCallback(() => { setshouldBlock(false) },[]) const handleBlockedNavigation = useCallback( nextLocation => { if ( !confirmedNavigation && nextLocation.location.pathname !== location.pathname ) { handleLeave(nextLocation) setLastLocation(nextLocation) return false } return true }, [confirmedNavigation] ) const confirmNavigation = useCallback(() => { setConfirmedNavigation(true) }, []) useEffect(() => { if (confirmedNavigation && lastLocation) { navigate(lastLocation.location.pathname) } }, [confirmedNavigation, lastLocation]) const provideLeaveHandler = handler => { handleLeave = handler } useBlocker(handleBlockedNavigation, shouldBlock) return ( <WrappedComponent {...props} provideLeaveHandler={provideLeaveHandler} setPreventNavigation={setShouldBlock} confirmNavigation={confirmNavigation} cancelNavigation={cancelNavigation} /> ) } }
over 4 years ago · Santiago Trujillo Report

0

Parece que está buscando el evento beforeunload .

Lea atentamente ya que no todos los navegadores cumplen con event.preventDefault() .

En el controlador de eventos, puede hacer las comprobaciones que desee y evitar que la ventana se cierre según sus requisitos.

Espero que esto ayude.

over 4 years ago · Santiago Trujillo Report

0

Esta respuesta usa el enrutador v6.

  1. Puedes usar usePrompt .
  • usePrompt mostrará el modal/ventana emergente de confirmación cuando vaya a otra ruta, es decir, en el montaje.
  • Una alerta genérica con mensaje cuando intenta cerrar el navegador. Maneja antes de descargar internamente
 usePrompt("Hello from usePrompt -- Are you sure you want to leave?", isBlocking);
  1. Puedes usar useBlocker
  • useBlocker simplemente bloqueará al usuario cuando intente navegar, es decir, al desmontar
  • Una alerta genérica con mensaje cuando intenta cerrar el navegador. Maneja antes de descargar internamente
 useBlocker( () => "Hello from useBlocker -- are you sure you want to leave?", isBlocking );

Demostración para 1 y 2

  1. También puede usar beforeunload . Pero tienes que hacer tu propia lógica. Vea un ejemplo aquí
over 4 years ago · Santiago Trujillo Report

0

Publicar esto para alguien que quiere un pop-up/modal box interfaz de usuario personalizado en lugar del default prompt del navegador y está usando react-router (v4) con history .

Puede hacer uso del custom history y configurar su router como

 import createBrowserHistory from 'history/createBrowserHistory' export const history = createBrowserHistory() ... import { history } from 'path/to/history'; <Router history={history}> <App/> </Router>

y luego en su componente de aviso personalizado puede hacer uso de history.block como

 import { history } from 'path/to/history'; class MyCustomPrompt extends React.Component { componentDidMount() { this.unblock = history.block(targetLocation => { // take your action here return false; }); } componentWillUnmount() { this.unblock(); } render() { //component render here } }

Agregue este MyCustomPrompt en sus componentes donde quiera bloquear la navegación.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!