Hola, estoy tratando de hacer una pequeña aplicación para React-router. Estoy tratando de enviar una solicitud de API (no tengo backend, por eso estoy usando promesas). estoy haciendo mal? Primero pensé que puedo pasar la historia con accesorios y luego
history.push("/someURL");Pero mi segundo pensamiento es si pudiera hacer esto con <Link, pasaré menos accesorios (historia).
Para resumir, necesito esperar hasta que termine mi solicitud (promesa), después de eso, necesito cambiar la URL
import React from 'react'; import PropTypes from 'prop-types'; import styled from 'styled-components'; import { Link } from 'react-router-dom'; import { toast } from 'react-toastify'; const StyledButton = styled.button` width: 100%; border-radius: 10px; background-color: #24b571; color: #ffffff; font-weight: bold; margin-bottom: 5px; `; const SaveButton = ({ children, saveValidation, message, to, setIsLoading, }) => { const promiseFunc = () => new Promise((resolve) => { setTimeout(() => { resolve(5); }, 5000); }); const onClickHandler = async (event) => { setIsLoading(true); const control = saveValidation(); // returns true or false if (!control) { toast.error(message); event.preventDefault(); } else { try { const a = await promiseFunc(); alert(a); } catch { alert('error'); } console.log(control); } setIsLoading(false); }; return ( <Link to={to}> <StyledButton onClick={onClickHandler}>{children}</StyledButton> </Link> ); }; export default SaveButton; SaveButton.propTypes = { children: PropTypes.node.isRequired, saveValidation: PropTypes.func.isRequired, to: PropTypes.string.isRequired, message: PropTypes.string, setIsLoading: PropTypes.func, }; SaveButton.defaultProps = { message: 'Fill all values', setIsLoading: () => {}, }; El problema principal aquí es que está representando DOS componentes/elementos con los que un usuario podría interactuar, lo que generalmente se considera antipatrón en UI/UX. Se hace clic en el botón y se invoca su controlador onClick , y el evento de clic burbujea y el Link lo maneja navegando. Estos eventos se manejan por separado unos de otros. Podría detener la propagación del evento onClick en el controlador de clic del botón, pero luego el Link dejaría de funcionar.
Sugiero usar el botón con estilo solo y al final de la lógica asincrónica emitir una navegación imperativa en lugar de la navegación declarativa que ofrece el Link . Use el useHistory de react-router-dom ( o useNavigate si usa RRDv6 ).
import React from 'react'; import PropTypes from 'prop-types'; import styled from 'styled-components'; import { useHistory } from 'react-router-dom'; // <-- import hook import { toast } from 'react-toastify'; const StyledButton = styled.button` ... `; const SaveButton = ({ children, saveValidation, message, setIsLoading, to, }) => { const history = useHistory(); // <-- use hook const promiseFunc = () => new Promise((resolve) => { ... }); const onClickHandler = async (event) => { setIsLoading(true); const control = saveValidation(); if (!control) { toast.error(message); event.preventDefault(); } else { try { const a = await promiseFunc(); alert(a); } catch { alert('error'); } console.log(control); } setIsLoading(false); history.push(to); // <-- imperative navigation }; return ( <StyledButton onClick={onClickHandler}>{children}</StyledButton> ); };