0

I've developed a React application for a book library based on what I learned in my university classes. The application manages a list of books, allowing users to view, rate, and delete books. I've structured my components as follows:

  • App.js (main component)
    • BookTable (renders the table of books)
      • BookTableRow (renders each row in the table)
        • StarRating (handles the star rating for each book)
          • Star (individual star component)

(App.js)

import './App.css';
import React, { useState, useEffect } from 'react';
import {books as bks} from './services/bookObject';
import BookTable from './components/bookTable';

function App() {
  const [books, updateBooks] = useState(bks);

  const initProcess = () => {
    const booksCurrent = books.map(book => ({
      ...book,
      rating: 0
    }));
    updateBooks(booksCurrent);
  };

  // execute only one time at first render
  useEffect(() => {
    initProcess();
  }, []);

  const handleDelete = (id) => {
    const booksCurrent = books.filter(book => book._id != id);
    updateBooks(booksCurrent);
  };

  const handleRating = (id, rating) => {
    const booksCurrent = books.map(book => {
      if (book._id === id) {
        book.rating = rating;
      }
      return book;
    });
    updateBooks(booksCurrent);

    console.log(books);
  }

  return (
    <div className="App">
      <h1>My Book Library</h1>
      <p>Showing {books.length} books</p>
      <BookTable
      books={books}
      handleDelete={handleDelete}
      handleRating={handleRating}/>
    </div>
  );
}

export default App;

(components/bookTable.jsx)

import React, { Component } from 'react';
import BookTableRow from './bookTableRow';


const BookTable = ({books, handleDelete = f => f, handleRating = f => f}) => {
    if (books.length === 0) {
        return (<p>There is no book infromation</p>);
    }
    return (
        <div className='books'>
            <table className="table">
                <thead>
                    <tr>
                        <th>Id</th>
                        <th>Title</th>
                        <th>Category</th>
                        <th>Author</th>
                        <th>Number In Stock</th>
                        <th>Price</th>
                        <th>Year</th>
                        <th>Review</th>
                        <th>Action(s)</th>
                    </tr>
                </thead>
                <tbody>
                    {
                        books.map((book, index) => (
                            <BookTableRow 
                            book={book}
                            onDelete={handleDelete}
                            onRating={handleRating}
                            />
                        ))
                    }
                </tbody>
            </table>
        </div>
    );
}

export default BookTable;

(components/bookTableRow.jsx)

import * as React from 'react';
import { Component } from 'react';

import StarRating from './starRating';

const BookTableRow = ({book, onDelete = f => f, onRating = f => f}) => {
    return (
        <tr>
            <td>{book._id}</td>
            <td>{book.title}</td>
            <td>{book.category.name}</td>
            <td>{book.author}</td>
            <td>{book.numberInStock}</td>
            <td>{book.price}</td>
            <td>{book.publishYear}</td>
            <td>
                <StarRating
                starCount={5}
                book={book}
                onRating={onRating}
            /></td>
            <td>
                <button className="btn btn-danger" onClick={() => onDelete(book._id)}>Delete</button>
            </td>
        </tr>
    );
}

export default BookTableRow;

(components/starRating.jsx)

import React, { Component, useState } from 'react';
import { FaStar } from 'react-icons/fa';

import { createArray } from '../services/createArray';
import Star from './star';

const StarRating = ({starCount, book, onRating = f => f}) => {

    return (
        <div>
            {
                createArray(starCount).map((n, i) => (
                    <Star 
                    book={book}
                    index={i}
                    isSelected={i < book.rating+1}
                    onClick={onRating}
                    />
                ))
            }
            <p> {book.rating+1} of {starCount} stars</p>
        </div>
    );
}
 
export default StarRating;

(components/star.jsx)

import React, { useState } from 'react';
import { FaStar } from 'react-icons/fa';

const Star = ({book, index, isSelected, onClick = f => f}) => {
    return (
        <div>
            <FaStar color={isSelected?"red": "gray"} onClick={() => onClick(book._id, index)}/>
        </div>
    );
}
 
export default Star;

services/bookObject.js

books = [
  (the list of book object)
]

export function getBooks() {
    return books;
}

(services/createArray.js)

import React, { Component } from 'react';

export const createArray = (length) => {
    return ([...Array(length)]);
}

My questions are:

  1. Is this level of component nesting (App > BookTable > BookTableRow > StarRating > Star) considered good practice in professional React development?
  2. Are there any potential issues or drawbacks with this approach?
  3. How might experienced React developers structure this differently, if at all?
  4. Are there any general guidelines for deciding when to create a new component versus keeping functionality in a parent component?

I'm looking to understand best practices in React component structuring as I transition from academic projects to professional development. Any insights or suggestions for improvement would be greatly appreciated.

2
  • 1. Looks good, I may have included the Star component in the StarRating component, though its elegant how you've done it. 2. Not when considering React promotes this type of componentization, beating Angulars behavioral style. 3. Same as #2. 4. General rules, when functionality can be reused, part of your UI has a distinct responsibility or behavior, component should do one thing well - single responsibility, or when component becomes too large with hundreds of lines or a large number of props lead to increased complexity, or when a component has to manage multiple pieces of state and etc Commented Oct 16, 2024 at 1:29
  • Thank you for your kind and infomative comment! Commented Oct 16, 2024 at 5:59

1 Answer 1

0

It is good to have different components. your approach is correct, as per the current Book library scenario. Developing a structure is based on the type of the project is, current is likely Software as a Service, and there are many different structure, varies based on which libraries you use, what is your personal taste, Which hooks, context, utils, libs you use. keep static data in a file called CONSTANT.js and TS types into TYPES.ts file if using Typescript.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.