Home > Net >  How to call react component in conditional statement inside another component
How to call react component in conditional statement inside another component

Time:02-24

I am new to react and I want to implement a notification popup showing either the error or success from an api response inside another component. This is the component I have for the notification with animation included where later I plan to have the props.message have the error message content:

export function MessagesComponent(props) {
    console.log("Notification triggered")
    let [message, setMessage] = useState("This is the error message")
    let [classes, setClasses] = useState('animate__bounceInDown error-message-color ')
    let [signClasses, setSignClasses] = useState(' ')
    useEffect(() => {
        setSignClasses(' error-sign-color')
    },[])
    useEffect(() => {
        let timer1 = setTimeout(() => setClasses('animate__bounceOutLeft error-message-color'), 3000)
        return () => {
            clearTimeout(timer1)
        }
    })
    return (
        <>
            <div className={classes.concat(' messages-wrapper  animate__animated error-message-color')} id="messages-wrapper">
                <div className={signClasses.concat(" message-sign")}><i className="bi bi-x-lg"></i></div>
                <div className="messages" id="messages">{message}</div>
            </div>
        </>
    )
}

It just makes it drop from the bottom and after some time it goes away. I have this in the index html document along my list component for testing and styling:

<div id="messages-component"></div>
<div id="categories-list"></div> 

This works and the animation triggers when I reload the page but now I want it to trigger only when there is an error. I have a category list that can be edited and the list component renders the following category component for each category the api fetches:

    export function Category(props) {
        let { category } = props
        let [categories, setCategory] = useState(category)
        let inputRef = React.createRef()
        let [updateStyle, setUpdateStyle] = useState('d-none')
        function handleUpdateBackend() {
            let currentValue = inputRef.current.value
            let handleUpdateBackend = (response, status) => {
                if (status === 200) {
                    setCategory(response)
                }
                else {
                    //Call the notification component
                }
            }
        apiPatchCategory(category.id, handleUpdateBackend, currentValue)
        setUpdateStyle('d-none')
    ...

Everything works fine and I had an alert() function for the message error displaying but I want it to be more personalized. I am not sure how to call the component to render only when the else statement executes. The reason I built a component is because I plan to reuse this in other areas where messages are needed. I tried calling it inside the else statement directly but no luck so there is something I am missing. This is what I have but as mentioned it triggers on reload: enter image description here

CodePudding user response:

You cannot call a component anywhere in your code, except in the render method of another React component. I suggest the following approach:

  • Create a React container component that lives somewhere in your app, which will serve to receive and display messages, and to animate them.
  • Create a message service that you can call to dispatch a new message.

You'll need the message service to expose a static method that you can call to create a new message. The container component, meanwhile, subscribes to the message services when it is created.

Here is some skeleton code for a message service:

/**
 * ToastService is used to create Toasts.
 * 
 * To create a Toast, do
 * 
 *   ToastService.toast(ReactNode, duration in ms[optional])
 */
class ToastService {
  private static subscriber: IToastSubscriber = null;

  /** 
   * Subscribe a ToastContainer to the ToastService.
   * There can only be a single subscriber (it does not
   * make sense to show toasts in more than one place).
   */ 
  public static subscribe(subscriber: IToastSubscriber) {
    ToastService.subscriber = subscriber;
  }

  /**
   * Create a new Toast.
   * @param message Message to show. This is a React Node.
   * @param duration (Optional) Toast duration in ms.
   */
  public static toast(message: React.ReactNode, duration?: number) {
    // Toasts are not created if there is no ToastContainer subscribed
    // to the ToastService.
    if(ToastService.subscriber == null) return;
    ToastService.subscriber.toast(message, duration);
  }
}

You would call this message service from your Category function:

ToastService.toast("An error occurred.");

For the message container, your React component might look like this (I'll leave most of the implementation details out):

class ToastContainer implements IToastSubscriber {
  constructor(props) {
    ToastService.subscribe(this);
    this.state = { messages: {} };
  }

  public toast(message: React.ReactNode, duration?: number) {
    // Add message to state.messages
  }

  ...

  render() {
    return(
      // For each message in state.messages, render a message component.
    );
  }
}

You'd use the duration of each message to eventually remove it from your list of messages.

CodePudding user response:

You can use ternary opeator to Display that message Component inside ur JSX

{someCondition ? <ErrorMessageComponent /> : null} // This will render the component when there is an error 

OR

{someCondition && <ErrorMessageComponent />} //Same thing

but make sure that u take care of ur removing error message properly otherwise it will alway's shown th div

  • Related