Setting Parent Component Modal Props From Other Child - ReactJS

Viewed 318

Firstly like to say that I am pretty new to React, however after scouring the internet for an answer to this one sadly nothing quite fits perfectly so here I am.

I have a component that holds a bootstrap modal which I then want to set the values of from another child and finally show the modal. While I could solve this problem by simply declaring the modal child inside the 2nd child component this would cause multiple renders of the modal for each child (generating a lot of redundant HTML code). So I want to declare the modal component in the parent and then somehow have its values set by the child when it is activated (I have created a basic version for ease of viewing):

function DeleteModal(props)
{
    return (
        <div className="modal" id="div_DeleteModal">
            <div className="modal-dialog modal-lg">
                <div className="modal-content">

                    <div className="modal-header">
                        <h4 className="modal-title text-center"><strong>Confirm Delete</strong></h4>
                        <button type="button" className="close" data-dismiss="modal">&times;</button>
                    </div>

                    <div className="modal-body">
                        <p>You are about to delete this option</p>
                    </div>

                    <div className="modal-footer">
                        <button type="button" title='Please Confirm Delete' className="btn btn-danger" data-dismiss="modal">Delete</button>
                        <button type="button" className="btn btn-link" data-dismiss="modal">Cancel</button>
                    </div>

                </div>
            </div>
        </div>
    );
}

class ChildObj extends React.Component 
{

    constructor(props)
    {
        super(props);
    }

    DeleteVal(optionVal)
    {
        //Pass values to parent's "DeleteModal" props somehow?

        //Show Modal
        $('#div_DeleteModal').modal('show')
    }

    render() 
    {
        return (
            <div>
                <h4>{this.props.name}</h4>
                {this.props.delOptions.map(delOption =>
                    <button type='button' onClick={() => this.DeleteVal({delOption})}>Delete {delOption}</button>
                )}
            </div>
        );
    }
}

//Main App
class App extends React.Component 
{
    constructor(props) 
    {
        super(props);

        this.childObjs = [
            {'Name' : 'Obj A', 'DelOptions' : ['Option A', 'Option B', 'Option C']},
            {'Name' : 'Obj B', 'DelOptions' : ['Option A', 'Option B', 'Option C']},
            {'Name' : 'Obj C', 'DelOptions' : ['Option A', 'Option B', 'Option C']}
        ];
    }

    render()
    {
        return(
            <div>
                <DeleteModal />
                <div>
                    {this.childObjs.map(childObj =>
                        <ChildObj name={childObj.Name} delOptions={childObj.DelOptions}  />
                    )}
                </div>
            </div>
        );
    }
}

ReactDOM.render(
    <App />,
    document.getElementById('ReactContent')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

<div id='ReactContent'>
</div>

Many Thanks in advance! :)

1 Answers

Thank you for the running code! Your approach to create a single copy of Delete Dialog is very good. Here are few things that you can do:

In React how to set and get data: To set data inside, add properties to a component and to get data out of the component, use property which have names like that of event like onChange, onClick etc.

  1. Add an onClick property to the ChildObj and call it like this.props.onClick(<Child-object-id-for-parent-to-use>)
  2. In the parent i.e. App handle this click event, use the the id passed in above step to get the child object from the childObjs array.
  3. In the parent have a state to open and close the dialog box and pass it to the DeleteModal as its property e.g. open. Internally DeleteModal will map this property to an open state to show and hide the modal box.
  4. In the parent have another state to keep reference of child object and pass it to the DeleteModal as its another property, may be 'data'. Internally DeleteModal will map this property to a data state to show values wherever you want to show in the modal box.
  5. In the DeleteModal modal box, have an onClose property which you would want to call from the Close button of the dialog box. Parent (App) will handle this close event to clear the selected child data and open property. This step is more of cleaning the references.
Related