DEV Community

Dhiren Patel
Dhiren Patel

Posted on

Creating Multiple Instances of a Dialog Tree in React.js

Description:
I'm working on a React.js application where I have a dialog tree that I need to open multiple times. Each time I open it, I want to create a new instance of the dialog tree. However, I'm encountering issues with this behavior. Instead of getting separate instances, the dialogs seem to be sharing some state.

Code Snippet:
`import React, { useCallback, useEffect } from 'react';
import arrowBackSvg from '../Images/arrow-back.svg';

const DialogTree = React.memo(({ bubble: { id, items }, onClickBubble, isOpen }) => {
const handleClosePopup = () => {
onClickBubble(null, null); // Notify the parent to close the dialog
};

const handleOnClick = useCallback((reference, title) => {
    handleClosePopup();
    onClickBubble(reference, title);
}, [onClickBubble]);

const renderLink = (item) => {
    const { id: itemId, title, kb_content_link } = item;
    const { reference } = kb_content_link.target;
    return (
        <button
            className='btn btn-1'
            title={item.title}
            onClick={() => handleOnClick(reference, title)}
        >
            {title}
        </button>
    );
};

const renderText = (item) => {
    const { id: itemId, title } = item;
    return (
        <button
            className='btn btn-2'
            title={title}
            onClick={() => handleOnClick(null, title)}
        >
            {title}
        </button>
    );
};

const renderDialogTreeContainer = () => {
    return items.map((item, index) => {
        if (item.type === 'link') {
            return renderLink(item);
        } else {
            return renderText(item);
        }
    });
};

useEffect(() => {
    if (isOpen) {
        // Add event listener to handle closing when the user clicks outside the dialog
        const handleOutsideClick = (e) => {
            if (!e.target.closest('.dialog-tree-bubble-container')) {
                handleClosePopup();
            }
        };

        document.addEventListener('mousedown', handleOutsideClick);

        return () => {
            // Remove the event listener when the component unmounts
            document.removeEventListener('mousedown', handleOutsideClick);
        };
    }
}, [isOpen]);


return (
    <div>
        {isOpen && (
            <div className={`dialog-tree-bubble-container`}>
                <div className='popup-content'>
                    <div className='button-container-wrapper'>
                        <div className='button-container'>
                            <div className='button-list'>
                                <div className='close-button' onClick={handleClosePopup}>
                                    <img src={arrowBackSvg} alt={'Arrow Back'} />
                                </div>
                                {renderDialogTreeContainer()}
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )}
    </div>
);
Enter fullscreen mode Exit fullscreen mode

});

export default DialogTree;

import React, { useEffect, useId, useState } from 'react';
import PropTypes from 'prop-types';
import DialogTreeBubble from './DialogTree/Index';

export {

DialogTreeBubble,
Enter fullscreen mode Exit fullscreen mode

};

const Index = ({ author, bubbles, isSatisfied, suggestions, message, callbackMethod, scrollToBottom,handleDialogClose,isDialogOpen }) => {
const [satisfactionMessage, setSatisfactionMessage] = useState('');
const id = useId();

const handleSatisfactionSubmit = (satisfied) => {
    scrollToBottom();
    setSatisfactionMessage(satisfied ? 'Thank you for your feedback!' : 'We apologize for any inconvenience caused.');
};

const handleLinkClick = (reference, title) => {
    callbackMethod(reference, title);
};

const getBubbleComponent = (bubble, index) => {
    switch (bubble.type) {

        case BUBBLES.DialogTree:
            return (<div>
                       {isDialogOpen && <DialogTreeBubble   id={id}
                                                            bubble={bubble}
                                                            onClickBubble={handleDialogClose}
                                                            isOpen={isDialogOpen}
                         />}
                   </div>);

        default:
            return '';
    }
};

const renderBotMessage = () => {
    return (<>
            {bubbles && bubbles.length > 0 && (bubbles.map((bubble, index) => (
                    <div className={`message message-${author}`} key={UUID()}>
                        {getBubbleComponent(bubble, index)}
                    </div>)))}


        </>);
};

const renderUserMessage = () => {
    return <div className={`message message-${author}`} key={UUID()}>
        <div className='message-content'>
            {message}
        </div>
    </div>;
};


return author === MESSAGE_SENDER.Bot ? renderBotMessage() : renderUserMessage();
Enter fullscreen mode Exit fullscreen mode

};

Index.propTypes = {
author: PropTypes.string.isRequired,
bubbles: PropTypes.array.isRequired,
isSatisfied: PropTypes.bool,
suggestions: PropTypes.array,
message: PropTypes.string,
callbackMethod: PropTypes.func.isRequired,
scrollToBottom: PropTypes.func,
};

export default Index;
`

Problem: When I open the dialog tree multiple times, they don't behave as separate instances. What am I missing here? How can I achieve the desired behavior?

@appreactjs @react

Top comments (1)

Collapse
 
thomasbnt profile image
Thomas Bnt

Hello ! Don't hesitate to put colors on your codeblock like this example for have to have a better understanding of your code 😎

console.log('Hello world!');
Enter fullscreen mode Exit fullscreen mode

Example of how to add colors and syntax in codeblocks