Search code examples
reactjsasp.netasp.net-mvcasp.net-core

How to handle button's onClick method from base file in current file


I've got an application with this stack: ASP.NET Core MVC + React.JS

Client side view

There is an issue I've been faced with. I've got a file Patients.js which return to the router some HTML code.

Patients.js:

import * as React from 'react';
import {
    Grid,
    Table,
    TableHeaderRow,
    TableSelection,
    TableColumnResizing
  } from '@devexpress/dx-react-grid-material-ui';
import {
    SortingState,
    IntegratedSorting,
    SelectionState,
    IntegratedSelection
  } from '@devexpress/dx-react-grid';
import { useEffect, useState } from "react";
import BaseToolbar from '../Base/BaseToolbar.js'

import '../styles/patients.css';

const URL = '/api/patients';

const columns = [
    { name: 'id', title: 'ID' },
    { name: 'lastName', title: 'Last name' },
    { name: 'firstName', title: 'First name' },
    { name: 'middleName', title: 'Middle name' },
    { name: 'age', title: 'Age' }
];

const defaultColumnWidths = [
    { columnName: 'id', width: 100 },
    { columnName: 'lastName', width: 200 },
    { columnName: 'firstName', width: 200 },
    { columnName: 'middleName', width: 200 },
    { columnName: 'age', width: 100 }
];

let rows = [];
const Patients = () => {
    const [allPatients, setPatients] = useState([]);

    const getPatients = async () => {
        let params = {
            method: 'GET',
            headers: new Headers()
        };
        const result = await fetch(URL, params);

        if (result.ok) {
            const patients =  await result.json();
            setPatients(patients);
            rows = patients;
            return patients;
        }

        return [];
    };

    useEffect(() => {
        getPatients();
    }, []);

    return (
        <div style={{width:'100%'}}>
            <div>
                <BaseToolbar></BaseToolbar>
            </div>
            <div style={{border: '1px LightGrey solid'}}>
                <Grid
                    rows={rows}
                    columns={columns}
                >
                    <SelectionState
                        selection={allPatients}
                        onSelectionChange={setPatients}
                    />
                    <SortingState
                        defaultSorting={[{ columnName: 'id', direction: 'asc' }]}
                        columnExtensions={[{ columnName: 'age', sortingEnabled: false}]}
                    /> 
                    <IntegratedSorting />
                    <IntegratedSelection />
                    <Table />
                    <TableColumnResizing defaultColumnWidths={defaultColumnWidths} />
                    <TableHeaderRow showSortingControls />
                    <TableSelection showSelectAll />
                </Grid>
            </div>
            
        </div>
    );
}

export default Patients;

Basically, you can see system exports Patients constant. There is a BaseToolbar html tag in return operator. BaseToolbar is located in other file:

BaseToolbar.js

import '../styles/buttons.css';
import '../styles/Base/BaseToolbar.css';

const BaseToolbar = () => {
    return (
        <div className='base-toolbar'>
            <button className="base-btn base-btn-sep toolbar-button icon-add">Add</button>
            <button className="base-btn base-btn-sep toolbar-button icon-edit">Edit</button>
            <button className="base-btn base-btn-sep toolbar-button icon-cancel">Remove</button>
        </div>
    );
};

export default BaseToolbar;

So my actual question is: how can I handle onClick event for this 3 buttons?

In my head it should be something like that, see edits below:

BaseToolbar.js

<button className="base-btn base-btn-sep toolbar-button icon-add" onClick='onBaseToolbarAddButtonClicked'>Add</button>

Patients.js - somewhere before return statement paste handler-method:

function onBaseToolbarAddButtonClicked() {
    // todo: implement me
}

I want it to be reusable for other files. Not the only for Patients.js Please, give me an answer what should I do. Is my construction viable at all? What the construction you can offer me instead of mine?


Solution

  • I suggest updating BaseToolbar to take three onClick callback handlers as props, assigned to each button respectively.

    const BaseToolbar = ({ onAdd, onEdit, onRemove }) => {
      return (
        <div className='base-toolbar'>
          <button
            className="base-btn base-btn-sep toolbar-button icon-add"
            type="button"
            onClick={onAdd}
          >
            Add
          </button>
          <button
            className="base-btn base-btn-sep toolbar-button icon-edit"
            type="button"
            onClick={onEdit}
          >
            Edit
          </button>
          <button
            className="base-btn base-btn-sep toolbar-button icon-cancel"
            type="button"
            onClick={onRemove}
          >
            Remove
          </button>
        </div>
      );
    };
    

    Declare and pass these handlers when rendering BaseToolbar.

    const Patients = () => {
      ...
    
      const AddHandler = () => { .... };
      const EditHandler = () => { .... };
      const RemoveHandler = () => { .... };
    
      return (
        <div style={{ width: '100%' }}>
          <div>
            <BaseToolbar
              onAdd={AddHandler}
              onEdit={EditHandler}
              onRemove={RemoveHandler}
            />
          </div>
          <div style={{ border: '1px LightGrey solid' }}>
            ...
          </div>
        </div>
      );
    }