Tengo un componente React llamado PopUpBanner que uso para mostrar mensajes. Por ejemplo, en mi componente de inicio de sesión, lo uso así. Si ocurre un error, configuro el estado bannerMessage para que tenga texto para que el banner muestre:
this.setState({ bannerMessage: { msg: error.message + ". Incorrect email address or password.", isError: true, }, });Así es como se usa el componente:
<PopUpBanner message={bannerMessage.msg} isError={bannerMessage.isError} ></PopUpBanner> Y aquí está la clase PopUpBanner :
import React, { Component } from "react"; class PopUpBanner extends Component { constructor(props) { super(props); this.state = { message: this.props.message, }; } // TODO : not in use reset = () => { this.resetId = setTimeout( function () { this.setState({ message: "" }); }.bind(this), 3000 ); }; componentDidMount() {} componentWillUnmount() { if (this.timeoutId) { clearTimeout(this.timeoutId); console.log("clearing time out"); } } render() { const message = this.props.message; const isError = this.props.isError; return ( <div style={message != "" ? { display: "block" } : { display: "none" }}> <div> {isError ? ( <div className="alert alert-danger text-center" role="alert" style={{ width: "50%", margin: "auto" }} > {message} </div> ) : ( <div className="alert alert-primary text-center" role="alert" style={{ width: "50%", margin: "auto" }} > {message} </div> )} </div> </div> ); } } export default PopUpBanner; El problema es que el PopUpBanner se muestra hasta que se actualiza la página o se navega a otra página.
Entonces, si observa la clase PopUpBanner , intenté usar setTimeout pero no pude terminarlo.
¿Alguna idea sobre cómo puedo transformar el componente PopUpBanner para que esté en un temporizador?
Veo dos opciones:
Manéjelo en el componente principal, solo representa PopUpBanner cuando debería estar allí, usando setTimeout para desencadenar una actualización de estado que vuelve a representar el elemento principal sin representar PopUpBanner .
Manéjelo en PopUpBanner , devolviendo null desde el render después de la expiración.
Preferiría el número 1 al número 2. Pero su código existente básicamente está haciendo el #2, solo tiene que ajustar el render para admitirlo:
render() { const message = this.props.message; if (!message) { return null; } // ...show the message...Pero como se discutió en los comentarios, no copiaría accesorios para afirmar así. Así que en vez:
constructor(props) { super(props); this.state = { expiredMessage: null, }; }luego para caducar un mensaje:
setupExpiration() { this.expirationTimer = setTimeout(() => { this.setState(() => ({expiredMessage: this.props.message})); }, 1000); // <== Or however long you want it showing }... al que llama desde un par de métodos de ciclo de vida:
componentDidMount() { this.setupExpiration(); } componentDidUpdate() { this.setupExpiration(); } y render se convierte en:
render() { const { expiredMessage } = this.state; const { message } = this.props; if (expiredMessage === message) { return null; } // ...show the message... Pero nuevamente, preferiría que el padre controle esto, eliminando PopUpBanner cuando no debería mostrarse:
class PopUpBanner extends React.Component { render() { const {message} = this.props; return <div className="banner">{message}</div>; } } class Parent extends React.Component { state = { message: null, }; constructor(props) { super(props); this.showMessage = this.showMessage.bind(this); this.messageTimer = 0; } showMessage() { clearTimeout(this.messageTimer); this.setState({message: "Hi there, I'm a banner"}); this.messageTimer = setTimeout(() => { this.setState({message: null}); }, 1000); } render() { const {message} = this.state; const {showMessage} = this; return <div className="with-banner"> {message && <PopUpBanner message={message} />} <div> <input type="button" value="Show Message" onClick={showMessage} /> </div> </div>; } }; ReactDOM.render(<Parent />, document.getElementById("root")); <div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>