authorsSlice Books

أنت لديك authorsSlice يجلب الكتّاب، إذن لا تحتاج slice جديد.
لكن أيضًا لا نريد فلترة الكتب من booksSlice لأنك تستخدم pagination للكتب، وبالتالي قد لا تكون كل الكتب موجودة في الستور.

إذن الطريقة الأفضل والأبسط في حالتك هي:

استخدم authorsSlice لجلب الكاتب مع كتبه في طلب واحد.

وهذا يتم عبر Strapi:

/authors/:id?populate[books][populate]=image
JavaScript

يعني:

author
   ├── name
   ├── image
   └── books[]
JavaScript
1️⃣ تعديل authorsSlice

📁 authorsSlice.js

نضيف thunk جديد:

export const getAuthorDetails = createAsyncThunk(
  "authors/getAuthorDetails",
  async (authorId) => {

    const { data } = await api.get(
      `/authors/${authorId}?populate[books][populate]=image`
    );

    return data.data;
  }
);
JavaScript
2️⃣ إضافة الحالة داخل slice
.addCase(getAuthorDetails.pending, (state) => {
  state.isLoading = true;
})

.addCase(getAuthorDetails.fulfilled, (state, action) => {

  state.isLoading = false;

  // بيانات الكاتب
  state.author = action.payload;

  // الكتب المرتبطة به
  state.books = action.payload.books;

})

.addCase(getAuthorDetails.rejected, (state, action) => {

  state.isLoading = false;
  state.error = action.error.message;

})
JavaScript

ويصبح الـ state مثل:

const initialState = {
  data: [],
  author: null,
  books: [],
  isLoading: false,
  error: null
};
JavaScript
3️⃣ كارد الكاتب

📁 AuthorCard.jsx

<Link to={`/author/${author.documentId}`}>
  <div className="author-card">

    <img
      src={`http://localhost:1337${author.image?.url}`}
      alt={author.name}
    />

    <h5>{author.name}</h5>

  </div>
</Link>
JavaScript
4️⃣ Route
<Route
  path="/author/:id"
  element={<AuthorDetails />}
/>
JavaScript

5️⃣ صفحة الكاتب

📁 AuthorDetails.jsx

import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useParams } from "react-router-dom";
import { getAuthorDetails } from "../../store/authorsSlice";
import Book from "../../components/Book/Book";

function AuthorDetails(){

  const { id } = useParams();
  const dispatch = useDispatch();

  const { author, books, isLoading } = useSelector(
    (state) => state.authors
  );

  useEffect(()=>{

    dispatch(getAuthorDetails(id));

  },[dispatch,id]);


  if(isLoading){
    return <h3>Loading...</h3>;
  }

  return(

    <div className="container my-5">

      {/* بيانات الكاتب */}

      <div className="text-center mb-5">

        <img
          src={`http://localhost:1337${author?.image?.url}`}
          width="120"
          className="rounded-circle"
          alt=""
        />

        <h2>{author?.name}</h2>

      </div>


      {/* كتب الكاتب */}

      <div className="row row-cols-lg-5">

        {books.map((book)=>(
          <Book key={book.id} book={book}/>
        ))}

      </div>

    </div>

  );

}

export default AuthorDetails;
JavaScript

ماذا يحدث الآن
Author Card
     ↓
Click
     ↓
/author/:id
     ↓
dispatch(getAuthorDetails)
     ↓
Strapi API
     ↓
author + books
     ↓
Redux store
     ↓
Render
JavaScript

لماذا هذه الطريقة الأفضل لمشروعك

لأنك:

✔ لديك authorsSlice
✔ تستخدم pagination للكتب
✔ تحتاج بيانات الكاتب
✔ تحتاج كتبه
JavaScript

وهذه الطريقة تحقق ذلك بطلب API واحد فقط.