Unleash the Power of Repositories - Introducing My CRUD Table React Component

Unleash the Power of Repositories - Introducing My CRUD Table React Component

What and why?

I am building a DoJo (Martial Arts School) manager as my participation in the Hashnode hackathon. The leader of a dojo should be able to manage the students, their contracts, payments and classes.

Because I have several different models, which can be CREATED, READ, UPDATED and DELETED, I took the approach of building a CRUD table, that just needs some information about how to access the model.

Models used for this project (and in this post):

  • student

  • master

What do I want to build?

  • I want to get a list of all existing documents for a given model, displayed in a table

  • I want the table to do the heavy lifting (loading, removing and creating documents via the passed-in repository)

Prerequisites

  • Repository pattern for your data access

  • This is only worth doing if you have a lot of CRUD Models

Implementation

1 - Get your repository in place

The following snippet shows the API of my InMemoryRepository. If you are curious about the actual implementation, find it here on GitHub.

export const BuildInMemoryRepositoryFor = (sampleData = [], filterHandler = (items, filter) => { return items; }) => {
    const items = sampleData; 
    let cache = [];
    return {
        create: (data) => {/*logic...*/},
        delete: (id) => {/*logic...*/},
        update: (id, updatePayload) => {/*logic...*/},
        list: (filter = undefined) => {/*logic...*/},
        get: (id) => {/*logic...*/},
        count: () => {/*logic...*/},
    }

}

This comes in handy. when I define the InMemoryRepository for my teacher and my student model.

// repositories.js

export const InMemoryMasterRepository = BuildInMemoryRepositoryFor([]);
export const InMemoryStudentRepository = BuildInMemoryRepositoryFor([]);

2 - Coding our CRUD table component

export function CrudTable({repository, headers}) {
  const [documents, setDocuments] = useState([]);
  useEffect(() => {
    const fetch = async () => {
      setDocuments((await repository.list())); // access our repository
    };
    fetch();
  }, []);

  const delete = async (document) => {
    await repository.delete(document);
  }

  return <table>
           <thead>
            {headers.map((header) => {
                return <th>{header}</th>;
            })}
            <th>Actions</th>
           </thead>
         <tbody>
            {documents.map((document) => {
                return <tr>
                    {headers.map((header) => {
                        return <td>{document[header]}</td>
                    })}
                    <td><p onClick={() => delete(document)}>Delete</p></td>
                </tr>
            }
        </tbody>
    </table> 
}

3 - Integrating it

Inside your page, you can now integrate the Crud table.

import {InMemoryMasterRepository} from './repositories.js';
export function DashboardPage() {
  return <CrudTable repository={InMemoryMasterRepository} headers={['first_name', 'last_name']}/>
}

4 - Wait; There is more to CRUD, isn't it?

Yes! In addition to READ and DELETE operations, my CRUD table also includes CREATE and UPDATE methods. To facilitate this, I've developed a versatile ResourceForm component. It allows you to define the fields to be displayed in the form and specify validation rules.

For a comprehensive implementation of the CRUD table, including the ResourceForm component, you can explore the complete code in my GitHub repository.

Limitations

Nothing is as great as it seems at first. The current approach is not able to populate any data. You would need to do this on the repository end of your data.

For example: if I want to map a student to a master. I can do this via the ID. This, however, will just display the id in the table, which is kind of nonsense.

Conclusion

You need to balance yourself and your project if you are going to need this. If you have a lot of models that should be viewable and editable in a similar way, then this might be a great approach for you.