On the pros and cons of multiple nesting in React component development

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.