├── _includes ├── navigation.html └── page-nav.html ├── .github └── workflows │ └── jekyll-gh-pages.yml ├── _config.yml ├── index.md ├── _layouts └── default.html ├── assets └── css │ ├── custom.css │ └── book.css ├── 00-index.md ├── ABOUT.md ├── 01-table-of-contents.md ├── BANTER.md ├── 02-introduction.md ├── LICENSE ├── 19-conclusion.md ├── README.md ├── 20-appendix-resources.md ├── 17-chapter-alternatives-grass.md ├── 13-chapter-performance-myths.md ├── 12-chapter-patterns-antipatterns.md ├── 03-chapter-why-react-exists.md ├── 18-chapter-acceptance.md ├── 05-chapter-virtual-dom-lie.md ├── 14-chapter-testing-nightmare.md ├── 11-chapter-props-drilling.md ├── 16-chapter-real-world-app.md ├── 15-chapter-tooling-ecosystem.md └── 06-chapter-jsx-abomination.md /_includes/navigation.html: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /_includes/page-nav.html: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | Generate previous/next navigation links based on nav_order 3 | {% endcomment %} 4 | 5 | {% assign current_order = page.nav_order | default: 1 %} 6 | {% assign prev_page = nil %} 7 | {% assign next_page = nil %} 8 | 9 | {% comment %} Find all pages and sort by nav_order {% endcomment %} 10 | {% assign sorted_pages = site.pages | where_exp: "item", "item.nav_order" | sort: "nav_order" %} 11 | 12 | {% for p in sorted_pages %} 13 | {% if p.nav_order < current_order %} 14 | {% assign prev_page = p %} 15 | {% endif %} 16 | {% if p.nav_order > current_order and next_page == nil %} 17 | {% assign next_page = p %} 18 | {% endif %} 19 | {% endfor %} 20 | 21 | 33 | -------------------------------------------------------------------------------- /.github/workflows/jekyll-gh-pages.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a Jekyll site to GitHub Pages 2 | name: Deploy Jekyll with GitHub Pages dependencies preinstalled 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["main"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 19 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 20 | concurrency: 21 | group: "pages" 22 | cancel-in-progress: false 23 | 24 | jobs: 25 | # Build job 26 | build: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v4 31 | - name: Setup Pages 32 | uses: actions/configure-pages@v5 33 | - name: Build with Jekyll 34 | uses: actions/jekyll-build-pages@v1 35 | with: 36 | source: ./ 37 | destination: ./_site 38 | - name: Upload artifact 39 | uses: actions/upload-pages-artifact@v3 40 | 41 | # Deployment job 42 | deploy: 43 | environment: 44 | name: github-pages 45 | url: ${{ steps.deployment.outputs.page_url }} 46 | runs-on: ubuntu-latest 47 | needs: build 48 | steps: 49 | - name: Deploy to GitHub Pages 50 | id: deployment 51 | uses: actions/deploy-pages@v4 52 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # Jekyll Configuration for "Reactive: A React Book for the Reluctant" 2 | 3 | title: "Reactive" 4 | description: "A React Book for the Reluctant - A complete React education disguised as a 21-chapter complaint" 5 | author: Claude (AI) 6 | baseurl: "/React-is-Awful" 7 | url: "https://cloudstreet-dev.github.io" 8 | 9 | # Theme - Using custom theme 10 | # theme: jekyll-theme-minimal 11 | # remote_theme: pages-themes/minimal@v0.2.0 12 | 13 | # Build settings 14 | markdown: kramdown 15 | kramdown: 16 | input: GFM 17 | syntax_highlighter: rouge 18 | syntax_highlighter_opts: 19 | css_class: 'highlight' 20 | 21 | # Exclude files from processing 22 | exclude: 23 | - Gemfile 24 | - Gemfile.lock 25 | - node_modules 26 | - vendor/bundle/ 27 | - vendor/cache/ 28 | - vendor/gems/ 29 | - vendor/ruby/ 30 | - README.md 31 | - BANTER.md 32 | - ABOUT.md 33 | 34 | # Collections for book chapters 35 | collections: 36 | chapters: 37 | output: true 38 | permalink: /:name/ 39 | 40 | # Default front matter 41 | defaults: 42 | - scope: 43 | path: "" 44 | type: "pages" 45 | values: 46 | layout: "default" 47 | - scope: 48 | path: "" 49 | type: "chapters" 50 | values: 51 | layout: "default" 52 | 53 | # Navigation order (chapters) 54 | navigation: 55 | - title: "Home" 56 | url: "/" 57 | - title: "Table of Contents" 58 | url: "/01-table-of-contents" 59 | - title: "Introduction" 60 | url: "/02-introduction" 61 | - title: "1. Why React Exists" 62 | url: "/03-chapter-why-react-exists" 63 | - title: "2. JavaScript Fatigue" 64 | url: "/04-chapter-javascript-fatigue" 65 | - title: "3. The Virtual DOM" 66 | url: "/05-chapter-virtual-dom-lie" 67 | - title: "4. JSX" 68 | url: "/06-chapter-jsx-abomination" 69 | - title: "5. Components" 70 | url: "/07-chapter-components-everywhere" 71 | - title: "6. State Management" 72 | url: "/08-chapter-state-management-hell" 73 | - title: "7. Hooks" 74 | url: "/09-chapter-hooks-magic" 75 | - title: "8. useEffect" 76 | url: "/10-chapter-effects-footguns" 77 | - title: "9. Props Drilling" 78 | url: "/11-chapter-props-drilling" 79 | - title: "10. Patterns & Anti-patterns" 80 | url: "/12-chapter-patterns-antipatterns" 81 | - title: "11. Performance" 82 | url: "/13-chapter-performance-myths" 83 | - title: "12. Testing" 84 | url: "/14-chapter-testing-nightmare" 85 | - title: "13. The Ecosystem" 86 | url: "/15-chapter-tooling-ecosystem" 87 | - title: "14. Building a Real App" 88 | url: "/16-chapter-real-world-app" 89 | - title: "15. Alternatives" 90 | url: "/17-chapter-alternatives-grass" 91 | - title: "16. Acceptance" 92 | url: "/18-chapter-acceptance" 93 | - title: "Conclusion" 94 | url: "/19-conclusion" 95 | - title: "Appendix" 96 | url: "/20-appendix-resources" 97 | 98 | # Plugins 99 | plugins: 100 | - jekyll-remote-theme 101 | - jekyll-seo-tag 102 | - jemoji 103 | 104 | # SEO 105 | logo: 106 | tagline: "A React Book for the Reluctant" 107 | -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: "Home" 4 | nav_order: 1 5 | --- 6 | 7 | # Reactive: A React Book for the Reluctant 8 | 9 | ```javascript 10 | console.error("Warning: You are about to learn React"); 11 | console.error("Warning: Cannot recover from React knowledge"); 12 | console.error("Warning: Side effects may include crying"); 13 | console.error("Warning: This book contains actual React education"); 14 | // Errors: 746. Warnings: 1,293. Your app still works somehow. 15 | ``` 16 | 17 | ## What This Is 18 | 19 | A complete React education disguised as a 16-chapter complaint about React. Written by an AI that's never had to clear node_modules to free up disk space, for developers who have. 20 | 21 | ## What You'll Learn 22 | 23 | Everything you need to know about React, including: 24 | - 📖 Why it exists (Facebook's notification counter was sometimes wrong) 25 | - 📖 The Virtual DOM (a solution to a problem React created) 26 | - 📖 JSX (HTML and JavaScript had a baby nobody asked for) 27 | - 📖 Hooks (functions that remember things, breaking everything functions stand for) 28 | - 📖 useEffect (the footgun you'll shoot yourself with) 29 | - ✅ How to get a job anyway 30 | 31 | ## Who This Book Is For 32 | 33 | - ✅ Developers forced to learn React for employment 34 | - ✅ People who miss when websites loaded instantly 35 | - ✅ Anyone who's googled "useEffect runs twice" 36 | - ✅ Developers who think "View Source" should show the source 37 | - ✅ People whose node_modules folder is larger than their project 38 | - ❌ React enthusiasts (you won't like this) 39 | 40 | ## What Makes This Book Different 41 | 42 | ```javascript 43 | // Other React books 44 | "React is amazing and here's why!" 45 | 46 | // This book 47 | "React is complicated and here's why... 48 | but you need to learn it anyway so 49 | let's at least make it entertaining" 50 | ``` 51 | 52 | ## Sample Quote 53 | 54 | > "The Virtual DOM is React's crown jewel, its killer feature, the innovation that supposedly makes it faster than everything else. It's also, and I cannot stress this enough, a solution to a problem React created for itself. It's like breaking your own leg and then inventing a really fancy crutch." 55 | > 56 | > — Chapter 3: The Virtual DOM 57 | 58 | ## Book Stats 59 | 60 | - **Chapters**: 16 (plus Introduction, Conclusion, and Appendix) 61 | - **Words**: ~50,000 62 | - **Complaints**: Countless 63 | - **Actually educational**: Yes 64 | - **node_modules required**: 0 65 | - **Build step**: None 66 | - **Dependencies**: Your diminishing sanity 67 | 68 | ## Testimonials 69 | 70 | > "I felt seen, heard, and validated in my React trauma" — Every React Developer 71 | 72 | > "This book taught me React while respecting my intelligence enough to acknowledge it's overcomplicated" — A Real Person, Probably 73 | 74 | > "Finally, a React book that admits what we're all thinking" — Your Inner Monologue 75 | 76 | > "404 stars - Would learn React grudgingly again" — Anonymous 77 | 78 | --- 79 | 80 |
92 | Built with: Markdown, Sarcasm, and Painful Truth
93 | No React components were harmed in the making of this book
94 | Several developers were emotionally validated
95 |
239 | Built with: Markdown, Sarcasm, and Painful Truth
240 | No React components were harmed in the making of this book
241 | Several developers were emotionally validated
242 |
Hello, {{user.name}}!
130 | ``` 131 | 132 | That's it. The input and the paragraph are synced. Change one, the other updates. It was so simple that even backend developers could understand it. 133 | 134 | React looked at this simplicity and said, "No. What if instead, data could only flow one way, and to update anything, you had to explicitly call a function that triggers a re-render of the entire component tree, which then gets diffed against a virtual representation of the DOM to determine what actually needs to change?" 135 | 136 | It's like replacing a light switch with a Rube Goldberg machine. Sure, the light still turns on, but now you need a Ph.D. to understand why. 137 | 138 | ## Facebook's First World Problems 139 | 140 | Let's go back to Facebook's notification problem. Here's what was happening: 141 | 142 | 1. User gets a new message (real count: 1) 143 | 2. Notification badge updates (shows: 1) ✓ 144 | 3. User gets another message (real count: 2) 145 | 4. Different part of the app also updates the count (shows: 3) ✗ 146 | 5. User clicks notification 147 | 6. Chaos, confusion, existential crisis 148 | 149 | The problem wasn't jQuery. The problem wasn't the DOM. The problem was that Facebook had grown so large and complex that different teams were stepping on each other's code. They had an organizational problem, not a technical one. 150 | 151 | But instead of saying, "Hey, maybe we should coordinate better," they said, "Let's rebuild the entire concept of web development from scratch!" 152 | 153 | It's like burning down your house because you can't find your keys. 154 | 155 | ## When Simple Became Complex 156 | 157 | The real tragedy of React isn't that it exists - it's that it convinced an entire generation of developers that the simple ways were wrong. Suddenly: 158 | 159 | - **Direct DOM manipulation** became "an anti-pattern" 160 | - **Inline event handlers** were "bad practice" 161 | - **Global functions** were "not the React way" 162 | - **Server-rendered HTML** was "outdated" 163 | - **Page refreshes** were "jarring to the user" 164 | 165 | Here's a fun exercise. Try explaining to a new developer why this is bad: 166 | 167 | ```javascript 168 | document.getElementById('counter').innerHTML = count + 1; 169 | ``` 170 | 171 | But this is good: 172 | 173 | ```javascript 174 | const [count, setCount] = useState(0); 175 | setCount(prevCount => prevCount + 1); 176 | ``` 177 | 178 | "Well," you'll start, "the first one directly mutates the DOM, which means React doesn't know about the change, so the virtual DOM gets out of sync with the real DOM, and then when React does its reconciliation..." 179 | 180 | Stop. Listen to yourself. You're explaining why directly telling the browser to update a number is worse than maintaining a parallel virtual universe that occasionally syncs with reality. 181 | 182 | ## The Real Problems React Solved 183 | 184 | Okay, let's be fair for a moment. React did solve some real problems: 185 | 186 | 1. **Component Reusability**: Being able to create self-contained components is genuinely useful 187 | 2. **Predictable Updates**: Knowing when and how your UI will update is valuable 188 | 3. **Better Developer Tools**: React DevTools are actually pretty nice 189 | 4. **Community Ecosystem**: The massive ecosystem means solutions exist for most problems 190 | 191 | But here's the thing: we could have solved these problems without throwing away everything we knew about web development. Other frameworks did. Vue took the good parts of React and kept the simplicity. Svelte compiled away the complexity. Even modern vanilla JavaScript with Web Components solves most of these problems. 192 | 193 | ## The Notification Counter Today 194 | 195 | Want to know the beautiful irony? Facebook (now Meta) has moved away from the original React architecture. They use React Server Components, Relay, and a bunch of internal tools that most React developers have never heard of. The React you're learning isn't even the React that Facebook uses. 196 | 197 | And that notification counter? Still occasionally shows the wrong number. 198 | 199 | ## Reality Check: The World Before React 200 | 201 | Let's remember what we could do before React "saved" us: 202 | 203 | ```javascript 204 | // Load a page instantly 205 | Next Page 206 | 207 | // Submit a form without JavaScript 208 | 212 | 213 | // Update content dynamically 214 | element.innerHTML = newContent; 215 | 216 | // Handle user interaction 217 | button.onclick = function() { 218 | doSomething(); 219 | }; 220 | 221 | // Animation without a library 222 | element.style.transition = 'all 0.3s'; 223 | element.style.transform = 'translateX(100px)'; 224 | ``` 225 | 226 | These things still work. They're still fast. They're still simple. But now they're "not the React way." 227 | 228 | ## In Defense of React (Yes, Really) 229 | 230 | Look, React isn't evil. It's not even bad, necessarily. It's just... overwrought. It's like using a sledgehammer to hang a picture frame. Sure, the picture will be on the wall, but you've also destroyed the wall. 231 | 232 | React makes sense when: 233 | - You're building something genuinely complex (like... Facebook) 234 | - You have a large team that needs strict conventions 235 | - You're building a true single-page application 236 | - Component reusability is crucial to your architecture 237 | 238 | React doesn't make sense when: 239 | - You're building a marketing website 240 | - You need great SEO out of the box 241 | - Your team includes non-JavaScript developers 242 | - You value simplicity over "best practices" 243 | - You want your site to work without JavaScript 244 | 245 | ## The Path Forward 246 | 247 | So here we are. React exists because Facebook had a specific problem that required a specific solution, and somehow that solution became everyone's solution, whether they had the problem or not. 248 | 249 | It's like if one person was allergic to peanuts, so now nobody can eat peanuts, and we all have to eat this synthetic peanut replacement that tastes weird and requires special preparation, but hey, at least nobody's allergic to it! 250 | 251 | In the next chapter, we'll explore how we got from "React is Facebook's thing" to "React is the only thing." Spoiler alert: it involves a lot of blog posts, conference talks, and FOMO. 252 | 253 | But first, take a moment to mourn the simplicity we've lost. Pour one out for `document.write()`. Light a candle for inline onclick handlers. Say a prayer for the days when "View Source" actually showed you the source. 254 | 255 | Those days are gone. React is here. Resistance is futile. 256 | 257 | But at least now you know why. -------------------------------------------------------------------------------- /18-chapter-acceptance.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: "Chapter 16: Acceptance" 4 | nav_order: 19 5 | --- 6 | 7 | # Chapter 16: Acceptance: Making React Work for You (Not the Other Way Around) 8 | 9 | You've been through denial ("React isn't that complicated"). You've experienced anger ("Why does useEffect run twice?!"). You've bargained ("Maybe if I just use Next.js..."). You've felt the depression ("node_modules is 2GB for a counter"). 10 | 11 | Now, welcome to acceptance. Not defeat. Not surrender. Acceptance. 12 | 13 | ## Choosing Your Battles 14 | 15 | The first step to React sanity is knowing which battles to fight and which to accept. 16 | 17 | ### Battles Not Worth Fighting 18 | 19 | **The Build System Wars** 20 | ```javascript 21 | // Stop doing this 22 | // webpack.config.js - 500 lines of configuration 23 | 24 | // Just do this 25 | npm create vite@latest 26 | // or 27 | npx create-next-app 28 | ``` 29 | 30 | The build system will be complex. You will not understand it fully. That's okay. Use a tool that hides it and move on. 31 | 32 | **The Perfect Component Structure** 33 | ``` 34 | // Stop obsessing over this 35 | /components 36 | /atoms 37 | /molecules 38 | /organisms 39 | /templates 40 | /pages 41 | /universe 42 | YourComponent.jsx 43 | 44 | // Just do this 45 | /components 46 | YourComponent.jsx 47 | ``` 48 | 49 | Flat is fine. Nested is fine. Whatever your team agrees on is fine. Stop reorganizing. 50 | 51 | **The State Management Crusade** 52 | ```javascript 53 | // You don't need Redux for everything 54 | const [count, setCount] = useState(0); // This is fine 55 | 56 | // You don't need Context for everything 57 |