Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 2024-05-24 - Unnecessary Recalculation on Re-render
**Learning:** This codebase frequently performs client-side filtering on static datasets (like `externalResources` or `categories`) directly inside component bodies. If these datasets are defined *inside* the component, they are recreated on every render, causing referential inequality that breaks React optimizations. Even if moved outside, the filtering operation itself re-runs on every state change (e.g., typing in a search bar), which can be computationally expensive if the dataset grows.
**Action:** When encountering components with derived filtered state (like list views or directories), always move static source arrays outside the component definition. Then, wrap the filtering logic in a `useMemo` hook with strict dependencies on the specific filter states to prevent expensive recalculations and unnecessary re-renders.
246 changes: 124 additions & 122 deletions src/pages/Documentaries.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useState, useMemo } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faBook,
Expand Down Expand Up @@ -26,6 +26,118 @@ import ErrorMessage from "../components/common/ErrorMessage";
import SkeletonLoader from "../components/common/SkeletonLoader";
import Button from "../components/common/Button";

const categories = [
{ id: "all", name: "All Resources", icon: faBook },
{ id: "html", name: "HTML", icon: faHtml5, color: "text-orange-600" },
{ id: "css", name: "CSS", icon: faCss3Alt, color: "text-blue-600" },
{
id: "javascript",
name: "JavaScript",
icon: faJsSquare,
color: "text-yellow-600",
},
{ id: "python", name: "Python", icon: faPython, color: "text-green-600" },
{ id: "react", name: "React", icon: faReact, color: "text-cyan-600" },
{ id: "node", name: "Node.js", icon: faNodeJs, color: "text-green-500" },
{
id: "database",
name: "Database",
icon: faDatabase,
color: "text-purple-600",
},
];

const externalResources = [
{
id: 1,
title: "W3Schools HTML Tutorial",
description: "Complete HTML tutorial with examples and exercises",
url: "https://www.w3schools.com/html/",
category: "html",
type: "Tutorial",
difficulty: "Beginner",
icon: faHtml5,
color: "bg-orange-100 text-orange-600",
},
{
id: 2,
title: "W3Schools CSS Tutorial",
description: "Learn CSS from basic to advanced with interactive examples",
url: "https://www.w3schools.com/css/",
category: "css",
type: "Tutorial",
difficulty: "Beginner",
icon: faCss3Alt,
color: "bg-blue-100 text-blue-600",
},
{
id: 3,
title: "JavaScript Guide - MDN",
description: "Comprehensive JavaScript documentation and guide",
url: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide",
category: "javascript",
type: "Documentation",
difficulty: "Intermediate",
icon: faJsSquare,
color: "bg-yellow-100 text-yellow-600",
},
{
id: 4,
title: "Python Official Tutorial",
description: "Official Python tutorial from python.org",
url: "https://docs.python.org/3/tutorial/",
category: "python",
type: "Official Docs",
difficulty: "Beginner",
icon: faPython,
color: "bg-green-100 text-green-600",
},
{
id: 5,
title: "React Documentation",
description: "Official React documentation and learning resources",
url: "https://react.dev/",
category: "react",
type: "Official Docs",
difficulty: "Intermediate",
icon: faReact,
color: "bg-cyan-100 text-cyan-600",
},
{
id: 6,
title: "Node.js Getting Started",
description: "Official Node.js guides and API documentation",
url: "https://nodejs.org/en/learn/getting-started/introduction-to-nodejs",
category: "node",
type: "Official Docs",
difficulty: "Intermediate",
icon: faNodeJs,
color: "bg-green-100 text-green-500",
},
{
id: 7,
title: "SQL Tutorial - W3Schools",
description: "Learn SQL for database management",
url: "https://www.w3schools.com/sql/",
category: "database",
type: "Tutorial",
difficulty: "Beginner",
icon: faDatabase,
color: "bg-purple-100 text-purple-600",
},
{
id: 8,
title: "Docker Get Started",
description: "Official Docker tutorial and documentation",
url: "https://docs.docker.com/get-started/",
category: "devops",
type: "Official Docs",
difficulty: "Intermediate",
icon: faDocker,
color: "bg-blue-100 text-blue-500",
},
];

const Documentaries = () => {
const [searchTerm, setSearchTerm] = useState("");
const [selectedCategory, setSelectedCategory] = useState("all");
Expand All @@ -37,129 +149,19 @@ const Documentaries = () => {
refetch,
} = useApi(documentariesApi.getAll);

const categories = [
{ id: "all", name: "All Resources", icon: faBook },
{ id: "html", name: "HTML", icon: faHtml5, color: "text-orange-600" },
{ id: "css", name: "CSS", icon: faCss3Alt, color: "text-blue-600" },
{
id: "javascript",
name: "JavaScript",
icon: faJsSquare,
color: "text-yellow-600",
},
{ id: "python", name: "Python", icon: faPython, color: "text-green-600" },
{ id: "react", name: "React", icon: faReact, color: "text-cyan-600" },
{ id: "node", name: "Node.js", icon: faNodeJs, color: "text-green-500" },
{
id: "database",
name: "Database",
icon: faDatabase,
color: "text-purple-600",
},
];

const externalResources = [
{
id: 1,
title: "W3Schools HTML Tutorial",
description: "Complete HTML tutorial with examples and exercises",
url: "https://www.w3schools.com/html/",
category: "html",
type: "Tutorial",
difficulty: "Beginner",
icon: faHtml5,
color: "bg-orange-100 text-orange-600",
},
{
id: 2,
title: "W3Schools CSS Tutorial",
description: "Learn CSS from basic to advanced with interactive examples",
url: "https://www.w3schools.com/css/",
category: "css",
type: "Tutorial",
difficulty: "Beginner",
icon: faCss3Alt,
color: "bg-blue-100 text-blue-600",
},
{
id: 3,
title: "JavaScript Guide - MDN",
description: "Comprehensive JavaScript documentation and guide",
url: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide",
category: "javascript",
type: "Documentation",
difficulty: "Intermediate",
icon: faJsSquare,
color: "bg-yellow-100 text-yellow-600",
},
{
id: 4,
title: "Python Official Tutorial",
description: "Official Python tutorial from python.org",
url: "https://docs.python.org/3/tutorial/",
category: "python",
type: "Official Docs",
difficulty: "Beginner",
icon: faPython,
color: "bg-green-100 text-green-600",
},
{
id: 5,
title: "React Documentation",
description: "Official React documentation and learning resources",
url: "https://react.dev/",
category: "react",
type: "Official Docs",
difficulty: "Intermediate",
icon: faReact,
color: "bg-cyan-100 text-cyan-600",
},
{
id: 6,
title: "Node.js Getting Started",
description: "Official Node.js guides and API documentation",
url: "https://nodejs.org/en/learn/getting-started/introduction-to-nodejs",
category: "node",
type: "Official Docs",
difficulty: "Intermediate",
icon: faNodeJs,
color: "bg-green-100 text-green-500",
},
{
id: 7,
title: "SQL Tutorial - W3Schools",
description: "Learn SQL for database management",
url: "https://www.w3schools.com/sql/",
category: "database",
type: "Tutorial",
difficulty: "Beginner",
icon: faDatabase,
color: "bg-purple-100 text-purple-600",
},
{
id: 8,
title: "Docker Get Started",
description: "Official Docker tutorial and documentation",
url: "https://docs.docker.com/get-started/",
category: "devops",
type: "Official Docs",
difficulty: "Intermediate",
icon: faDocker,
color: "bg-blue-100 text-blue-500",
},
];

const filteredResources = externalResources.filter((resource) => {
const matchesSearch =
!searchTerm ||
resource.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
resource.description.toLowerCase().includes(searchTerm.toLowerCase());
const filteredResources = useMemo(() => {
return externalResources.filter((resource) => {
const matchesSearch =
!searchTerm ||
resource.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
resource.description.toLowerCase().includes(searchTerm.toLowerCase());

const matchesCategory =
selectedCategory === "all" || resource.category === selectedCategory;
const matchesCategory =
selectedCategory === "all" || resource.category === selectedCategory;

return matchesSearch && matchesCategory;
});
return matchesSearch && matchesCategory;
});
}, [searchTerm, selectedCategory]);

const getDifficultyColor = (difficulty) => {
switch (difficulty) {
Expand Down