Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Solid for React Developers

Solid for React Developers

In 2023, Solid JS is poised to be the next big frontend framework. Its underlying fundamentals are fundamentally different from React's. This talk will expose my learnings as I have approached Solid from the perspective of a React developer.

Erik Rasmussen

September 29, 2023
Tweet

More Decks by Erik Rasmussen

Other Decks in Programming

Transcript

  1. Erik Rasmussen – @erikras Declarative Programming function App() { const

    [highlighted, setHighlighted] = React.useState(false); return ( <div> <button>Highlight</button> <div>Hello!</div> </div> ); }
  2. Erik Rasmussen – @erikras Declarative Programming function App() { const

    [highlighted, setHighlighted] = React.useState(false); return ( <div> <button onClick={() = setHighlighted(true)}>Highlight</button> <div>Hello!</div> </div> ); }
  3. Erik Rasmussen – @erikras Declarative Programming function App() { const

    [highlighted, setHighlighted] = React.useState(false); return ( <div> <button onClick={() = setHighlighted(true)}>Highlight</button> <div className={highlighted ? "highlighted" : ""}>Hello!</div> </div> ); }
  4. Erik Rasmussen – @erikras Reactive Programming is a declarative programming

    paradigm built on data-centric event emitters – Ryan Carniato @ryancarniato
  5. Erik Rasmussen – @erikras Reactive Programming let a = 3;

    let b = 4; let sum = a + b; console.log(sum); // 7 Imperative Programming
  6. Erik Rasmussen – @erikras Reactive Programming let a = 3;

    let b = 4; let sum = a + b; console.log(sum); // 7 a = 5; Imperative Programming
  7. Erik Rasmussen – @erikras Reactive Programming let a = 3;

    let b = 4; let sum = a + b; console.log(sum); // 7 a = 5; console.log(sum); // 7 Imperative Programming 🙄
  8. Erik Rasmussen – @erikras Reactive Programming let a = 3;

    let b = 4; let sum = a + b; console.log(sum); // 7 a = 5; console.log(sum); // 9 Imperative Programming 🤯
  9. Erik Rasmussen – @erikras Reactive Programming let a = ()

    => 3; let b = () => 4; let sum = () => a() + b(); console.log(sum()); // 7
  10. Erik Rasmussen – @erikras Reactive Programming let a = ()

    => 3; let b = () => 4; let sum = () => a() + b(); console.log(sum()); // 7 a = () = 5; console.log(sum()); // 9 😎
  11. Erik Rasmussen – @erikras Signal a value that remembers everyone

    that reads it, and informs them when the value changes – Erik Rasmussen @erikras
  12. Erik Rasmussen – @erikras Signals in Solid const [value, setValue]

    = createSignal(0); console.log(value()); // 0
  13. Erik Rasmussen – @erikras Signals in Solid const [value, setValue]

    = createSignal(0); console.log(value()); // 0 setValue(42); console.log(value()); // 42 FOOTGUN #1: Signal values are getter functions!
  14. Erik Rasmussen – @erikras Signals in Solid const [value, setValue]

    = createSignal(0); console.log(value()); // 0 setValue(42); console.log(value()); // 42
  15. Erik Rasmussen – @erikras Signals in Solid const [getValue, setValue]

    = createSignal(0); console.log(getValue()); // 0 setValue(42); console.log(getValue()); // 42
  16. Erik Rasmussen – @erikras Signals in Solid const [value, setValue]

    = createSignal(0); console.log(value()); // 0 setValue(42); console.log(value()); // 42
  17. Erik Rasmussen – @erikras Derived Signals in Solid const [count,

    setCount] = createSignal(0); const double = () => count() * 2;
  18. Erik Rasmussen – @erikras Derived Signals in Solid const [count,

    setCount] = createSignal(0); const double = () => count() * 2; const increment = () => setCount(count() + 1);
  19. Erik Rasmussen – @erikras Derived Signals in Solid const [count,

    setCount] = createSignal(0); const double = () => count() * 2; const increment = () => setCount(count() + 1); console.log(count(), double()); // 0 0 increment(); console.log(count(), double()); // 1 2 increment(); console.log(count(), double()); // 2 4
  20. Erik Rasmussen – @erikras React Solid export const MyComponent =

    () => { return ( <div> <h1>Pop Quiz</h1> <div>What library is this?</div> </div> ); }; export const MyComponent = () => { return ( <div> <h1>Pop Quiz</h1> <div>What library is this?</div> </div> ); };
  21. Erik Rasmussen – @erikras React Solid export const MyComponent =

    () => { return ( <div> <h1>Pop Quiz</h1> <div>What library is this?</div> </div> ); }; export const MyComponent = () => { return ( <div> <h1>Pop Quiz</h1> <div>What library is this?</div> </div> ); };
  22. Erik Rasmussen – @erikras React Solid • Divide UI into

    "components" • Components are just functions • Components take props • Components output JSX • Component composition via JSX BOTH
  23. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS COUNTER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); return ( <div> <h1>{count}</h1> <button onClick={ () = setCount(count + 1) }>➕</button> </div> ); }; export const Counter = () => { const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={ () = setCount(count() + 1) }>➕</button> </div> ); };
  24. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS COUNTER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); return ( <div> <h1>{count}</h1> <button onClick={ () = setCount(count + 1) }>➕</button> </div> ); }; export const Counter = () => { const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={ () = setCount(count() + 1) }>➕</button> </div> ); };
  25. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS COUNTER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); return ( <div> <h1>{count}</h1> <button onClick={ () = setCount(count + 1) }>➕</button> </div> ); }; export const Counter = () => { const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={ () = setCount(count() + 1) }>➕</button> </div> ); };
  26. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS COUNTER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); return ( <div> <h1>{count}</h1> <button onClick={ () = setCount(count + 1) }>➕</button> </div> ); }; export const Counter = () => { const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={ () = setCount(count() + 1) }>➕</button> </div> ); };
  27. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS COUNTER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); return ( <div> <h1>{count}</h1> <button onClick={ setCount((previous) = previous + 1) }>➕</button> </div> ); }; export const Counter = () => { const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={ () = setCount(count() + 1) }>➕</button> </div> ); };
  28. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS COUNTER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); return ( <div> <h1>{count}</h1> <button onClick={ setCount((previous) = previous + 1) }>➕</button> </div> ); }; export const Counter = () => { const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={ setCount((previous) = previous + 1) }>➕</button> </div> ); };
  29. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS COUNTER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); return ( <div> <h1>{count}</h1> <button onClick={ setCount((previous) = previous + 1) }>➕</button> </div> ); }; export const Counter = () => { const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={ setCount((previous) = previous + 1) }>➕</button> </div> ); };
  30. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS TIMER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); return ( <div> <h1>{count}</h1> <button onClick={ (previous) = setCount(previous + 1) }>➕</button> </div> ); }; export const Counter = () const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={ (previous) }>➕</button> </div> ); };
  31. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS TIMER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); return ( <div> <h1>{count}</h1> </div> ); }; export const Counter = () const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={ (previous) }>➕</button> </div> ); };
  32. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS TIMER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); useEffect(() => { }) return ( <div> <h1>{count}</h1> </div> ); }; export const Counter = () const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={ (previous) }>➕</button> </div> ); };
  33. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS TIMER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); useEffect(() => { const interval = setInterval(() => { setCount(count + 1); }, 1000); }); return ( <div> <h1>{count}</h1> </div> ); }; export const Counter = () const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={ (previous) }>➕</button> </div> ); };
  34. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS TIMER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); useEffect(() => { const interval = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(interval); }); return ( <div> <h1>{count}</h1> </div> ); }; export const Counter = () const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={ (previous) }>➕</button> </div> ); };
  35. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS TIMER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); useEffect(() => { const interval = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(interval); }, [count]); return ( <div> <h1>{count}</h1> </div> ); }; export const Counter = () const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={ (previous) }>➕</button> </div> ); };
  36. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS TIMER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); useEffect(() => { const interval = setInterval(() => { setCount((previous) => previous + 1); }, 1000); return () => clearInterval(interval); }, []); return ( <div> <h1>{count}</h1> </div> ); }; export const Counter = () const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={ (previous) }>➕</button> </div> ); };
  37. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS TIMER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); useEffect(() => { const interval = setInterval(() => { setCount((previous) => previous + 1); }, 1000); return () => clearInterval(interval); }, []); return ( <div> <h1>{count}</h1> </div> ); }; export const Counter = () => { const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={ (previous) = setCount(previous + 1) }>➕</button> </div> ); };
  38. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS TIMER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); useEffect(() => { const interval = setInterval(() => { setCount((previous) => previous + 1); }, 1000); return () => clearInterval(interval); }, []); return ( <div> <h1>{count}</h1> </div> ); }; export const Counter = () => { const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> </div> ); };
  39. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS TIMER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); useEffect(() => { const interval = setInterval(() => { setCount((previous) => previous + 1); }, 1000); return () => clearInterval(interval); }, []); return ( <div> <h1>{count}</h1> </div> ); }; export const Counter = () => { const [count, setCount] = createSignal(0); setInterval(() => { setCount((previous) => previous + 1); }); return ( <div> <h1>{count()}</h1> </div> ); };
  40. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS TIMER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); useEffect(() => { const interval = setInterval(() => { setCount((previous) => previous + 1); }, 1000); return () => clearInterval(interval); }, []); return ( <div> <h1>{count}</h1> </div> ); }; export const Counter = () => { const [count, setCount] = createSignal(0); setInterval(() => { setCount((previous) => previous + 1); }); onCleanup(() => clearInterval(interval)); return ( <div> <h1>{count()}</h1> </div> ); };
  41. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS TIMER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); useEffect(() => { const interval = setInterval(() => { setCount((previous) => previous + 1); }, 1000); return () => clearInterval(interval); }, []); return ( <div> <h1>{count}</h1> </div> ); }; export const Counter = () => { const [count, setCount] = createSignal(0); setInterval(() => { setCount((previous) => previous + 1); }); onCleanup(() => clearInterval(interval)); return ( <div> <h1>{count()}</h1> </div> ); };
  42. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS TIMER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); useEffect(() => { const interval = setInterval(() => { setCount((previous) => previous + 1); }, 1000); return () => clearInterval(interval); }, []); return ( <div> <h1>{count}</h1> </div> ); }; export const Counter = () => { const [count, setCount] = createSignal(0); setInterval(() => { setCount((previous) => previous + 1); }); onCleanup(() => clearInterval(interval)); return ( <div> <h1>{count()}</h1> </div> ); }; FOOTGUN #2: The component function is only called once!
  43. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS TIMER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); useEffect(() => { const interval = setInterval(() => { setCount((previous) => previous + 1); }, 1000); return () => clearInterval(interval); }, []); return ( <div> <h1>{count}</h1> </div> ); }; export const Counter = () => { const [count, setCount] = createSignal(0); setInterval(() => { setCount((previous) => previous + 1); }); onCleanup(() => clearInterval(interval)); return ( <div> <h1>{count()}</h1> </div> ); };
  44. Erik Rasmussen – @erikras React Solid THE UBIQUITOUS TIMER EXAMPLE

    export const Counter = () => { const [count, setCount] = useState(0); useEffect(() => { const interval = setInterval(() => { setCount((previous) => previous + 1); }, 1000); return () => clearInterval(interval); }, []); return ( <div> <h1>{count}</h1> </div> ); }; export const Counter = () => { const [count, setCount] = createSignal(0); setInterval(() => { setCount((previous) => previous + 1); }); onCleanup(() => clearInterval(interval)); return ( <div> <h1>{count()}</h1> </div> ); }; HOOKS JSX RUN ON MOUNT JSX
  45. Erik Rasmussen – @erikras React Solid is "just JavaScript" that

    re-renders to Virtual DOM every time data changes, and performs a diff to know which DOM elements to update is a compiled template language that remembers which DOM elements depend on which state
  46. Erik Rasmussen – @erikras Solid export const Counter = ()

    => { const [count, setCount] = createSignal(0); setInterval(() => { setCount((previous) => previous + 1); }); onCleanup(() => clearInterval(interval)); return ( <div> <h1>{count()}</h1> </div> ); };
  47. Erik Rasmussen – @erikras Solid export const Counter = ()

    => { const [count, setCount] = createSignal(0); setInterval(() => { setCount((previous) => previous + 1); }); onCleanup(() => clearInterval(interval)); const doubleCount = count() * 2; return ( <div> <h1>{doubleCount}</h1> </div> ); };
  48. Erik Rasmussen – @erikras Solid export const Counter = ()

    => { const [count, setCount] = createSignal(0); setInterval(() => { setCount((previous) => previous + 1); }); onCleanup(() => clearInterval(interval)); const doubleCount = count() * 2; return ( <div> <h1>{doubleCount}</h1> </div> ); }; 1. Code before return happens only once!
  49. Erik Rasmussen – @erikras Solid export const Counter = ()

    => { const [count, setCount] = createSignal(0); setInterval(() => { setCount((previous) => previous + 1); }); onCleanup(() => clearInterval(interval)); const doubleCount = count() * 2; return ( <div> <h1>{doubleCount}</h1> </div> ); }; 1. Code before return happens only once! 2. JSX should never output a value that's not a signal (because otherwise it would never update) FOOTGUN #3: Only use signals in JSX. Never "get" their value before the JSX.
  50. Erik Rasmussen – @erikras React Solid export const User =

    (props) => { const { firstName, lastName, photoUrl } = props; return ( <div> <img src={photoUrl} alt={`${firstName} ${lastName}`} /> {firstName} {lastName} </div> ); }; PROPS export const User = (props) => { const { firstName, lastName, photoUrl } = props; return ( <div> <img src={photoUrl} alt={`${firstName} ${lastName}`} /> {firstName} {lastName} </div> ); };
  51. Erik Rasmussen – @erikras React Solid export const User =

    (props) => { const { firstName, lastName, photoUrl } = props; return ( <div> <img src={photoUrl} alt={`${firstName} ${lastName}`} /> {firstName} {lastName} </div> ); }; PROPS export const User = (props) => { const { firstName, lastName, photoUrl } = props; return ( <div> <img src={photoUrl} alt={`${firstName} ${lastName}`} /> {firstName} {lastName} </div> ); }; 🧙 { get firstName() {} get lastName() {} get photoUrl() {} } 🚩 FOOTGUN #3: Only use signals in JSX. Never "get" their value before the JSX. FOOTGUN #4: Never destructure props!
  52. Erik Rasmussen – @erikras React Solid export const User =

    (props) => { const { firstName, lastName, photoUrl } = props; return ( <div> <img src={photoUrl} alt={`${firstName} ${lastName}`} /> {firstName} {lastName} </div> ); }; PROPS export const User = (props) => { const { firstName, lastName, photoUrl } = props; return ( <div> <img src={photoUrl} alt={`${firstName} ${lastName}`} /> {firstName} {lastName} </div> ); };
  53. Erik Rasmussen – @erikras React Solid export const User =

    (props) => { const { firstName, lastName, photoUrl } = props; return ( <div> <img src={photoUrl} alt={`${firstName} ${lastName}`} /> {firstName} {lastName} </div> ); }; PROPS export const User = (props) => { const { firstName, lastName, photoUrl } = props; return ( <div> <img src={props.photoUrl} alt={`${props.firstName} ${props.lastName}`} /> {props.firstName} {props.lastName} </div> ); };
  54. Erik Rasmussen – @erikras React Solid export const User =

    (props) => { const { firstName, lastName, photoUrl } = props; return ( <div> <img src={photoUrl} alt={`${firstName} ${lastName}`} /> {firstName} {lastName} </div> ); }; PROPS export const User = (props) => { return ( <div> <img src={props.photoUrl} alt={`${props.firstName} ${props.lastName}`} /> {props.firstName} {props.lastName} </div> ); }; ✅
  55. Erik Rasmussen – @erikras React Solid export const User =

    (props) => { const { firstName = "Erik", lastName = "Rasmussen", photoUrl } = props; return ( <div> <img src={photoUrl} alt={`${firstName} ${lastName}`} /> {firstName} {lastName} </div> ); }; DEFAULT PROPS export const User = (props) => { const { firstName = "Erik", lastName = "Rasmussen", photoUrl } = props; return ( <div> <img src={photoUrl} alt={`${firstName} ${lastName}`} /> {firstName} {lastName} </div> ); };
  56. Erik Rasmussen – @erikras React Solid export const User =

    (props) => { const { firstName = "Erik", lastName = "Rasmussen", photoUrl } = props; return ( <div> <img src={photoUrl} alt={`${firstName} ${lastName}`} /> {firstName} {lastName} </div> ); }; DEFAULT PROPS export const User = (props) => { const { firstName = "Erik", lastName = "Rasmussen", photoUrl } = props; return ( <div> <img src={photoUrl} alt={`${firstName} ${lastName}`} /> {firstName} {lastName} </div> ); };
  57. Erik Rasmussen – @erikras React Solid export const User =

    (props) => { const { firstName = "Erik", lastName = "Rasmussen", photoUrl } = props; return ( <div> <img src={photoUrl} alt={`${firstName} ${lastName}`} /> {firstName} {lastName} </div> ); }; DEFAULT PROPS export const User = (props) => { const merged = mergeProps( { firstName: "Erik", lastName: "Rasmussen", }, props ); return ( <div> <img src={photoUrl} alt={`${firstName} ${lastName}`} /> {firstName} {lastName} </div> ); };
  58. Erik Rasmussen – @erikras React Solid export const User =

    (props) => { const { firstName = "Erik", lastName = "Rasmussen", photoUrl } = props; return ( <div> <img src={photoUrl} alt={`${firstName} ${lastName}`} /> {firstName} {lastName} </div> ); }; DEFAULT PROPS export const User = (props) => { const merged = mergeProps( { firstName: "Erik", lastName: "Rasmussen", }, props ); return ( <div> <img src={merged.photoUrl} alt={`${merged.firstName} ${merged.lastName}`} /> {merged.firstName} {merged.lastName} </div> ); }; ✅
  59. Erik Rasmussen – @erikras React Solid useEffect is the single

    most dangerous hook in React – Erik Rasmussen @erikras probably plagiarizing David "Khourshid" 🎹 @davidkpiano probably plagiarizing Dan Abramov @dan_abramov
  60. Erik Rasmussen – @erikras React Solid useE ff ect •Adding

    event listeners •Fetching data •Subscribing to data sources •Scheduling timeouts/intervals in component before return
  61. Erik Rasmussen – @erikras React Solid useE ff ect •Play

    a sound when data changes •Debounced save •Save state to localStorage createE ff ect
  62. Erik Rasmussen – @erikras React Solid export const Counter =

    () => { const [count, setCount] = useState(0); return ( <div> <h1>{count}</h1> <button onClick={(previous) = setCount(previous + 1) } > ➕ </button> </div> ); }; E ff ects
  63. Erik Rasmussen – @erikras React Solid export const Counter =

    () => { const [count, setCount] = useState(0); useEffect(() => { console.log("Count is now:", count); }); return ( <div> <h1>{count}</h1> <button onClick={(previous) = setCount(previous + 1) } > ➕ </button> </div> ); }; useE ff ect
  64. Erik Rasmussen – @erikras React Solid export const Counter =

    () => { const [count, setCount] = useState(0); useEffect(() => { console.log("Count is now:", count); }, [count]); return ( <div> <h1>{count}</h1> <button onClick={(previous) = setCount(previous + 1) } > ➕ </button> </div> ); }; useE ff ect
  65. Erik Rasmussen – @erikras React Solid export const Counter =

    () => { const [count, setCount] = useState(0); useEffect(() => { console.log("Count is now:", count); }, [count]); return ( <div> <h1>{count}</h1> <button onClick={(previous) = setCount(previous + 1) } > ➕ </button> </div> ); }; useE ff ect export const Counter = () => { const [count, setCount] = createSignal(0); return ( <div> <h1>{count()}</h1> <button onClick={(previous) = setCount(previous + 1) } > ➕ </button> </div> ); };
  66. Erik Rasmussen – @erikras React Solid export const Counter =

    () => { const [count, setCount] = useState(0); useEffect(() => { console.log("Count is now:", count); }, [count]); return ( <div> <h1>{count}</h1> <button onClick={(previous) = setCount(previous + 1) } > ➕ </button> </div> ); }; useE ff ect export const Counter = () => { const [count, setCount] = createSignal(0); createEffect(() => { console.log("Count is now:", count()); }); return ( <div> <h1>{count()}</h1> <button onClick={(previous) = setCount(previous + 1) } > ➕ </button> </div> ); };
  67. Erik Rasmussen – @erikras React Solid export const Counter =

    () => { const [count, setCount] = useState(0); useEffect(() => { console.log("Count is now:", count); }, [count]); return ( <div> <h1>{count}</h1> <button onClick={(previous) = setCount(previous + 1) } > ➕ </button> </div> ); }; useE ff ect export const Counter = () => { const [count, setCount] = createSignal(0); createEffect(() => { console.log("Count is now:", count()); }, [count]); return ( <div> <h1>{count()}</h1> <button onClick={(previous) = setCount(previous + 1) } > ➕ </button> </div> ); };
  68. Erik Rasmussen – @erikras React Solid export const Counter =

    () => { const [count, setCount] = useState(0); useEffect(() => { console.log("Count is now:", count); }, [count]); return ( <div> <h1>{count}</h1> <button onClick={(previous) = setCount(previous + 1) } > ➕ </button> </div> ); }; useE ff ect export const Counter = () => { const [count, setCount] = createSignal(0); createEffect(() => { console.log("Count is now:", count()); }); return ( <div> <h1>{count()}</h1> <button onClick={(previous) = setCount(previous + 1) } > ➕ </button> </div> ); }; NO DEPENDENCY ARRAY NEEDED!!
  69. Erik Rasmussen – @erikras React Solid export const Counter =

    () => { const [count, setCount] = useState(0); useEffect(() => { console.log("Count is now:", count); }, [count]); return ( <div> <h1>{count}</h1> <button onClick={(previous) = setCount(previous + 1) } > ➕ </button> </div> ); }; useE ff ect export const Counter = () => { const [count, setCount] = createSignal(0); createEffect(() => { console.log("Count is now:", count()); }); return ( <div> <h1>{count()}</h1> <button onClick={(previous) = setCount(previous + 1) } > ➕ </button> </div> ); };
  70. Erik Rasmussen – @erikras React Solid export const Result =

    (props) => { const expensiveResult = expensiveCalculation(props.value); return ( <div> <h1> The result is: {expensiveResult} </h1> </div> ); }; useMemo
  71. Erik Rasmussen – @erikras React Solid export const Result =

    (props) => { const expensiveResult = useMemo( () = expensiveCalculation(props.value) ); return ( <div> <h1> The result is: {expensiveResult} </h1> </div> ); }; useMemo
  72. Erik Rasmussen – @erikras React Solid export const Result =

    (props) => { const expensiveResult = useMemo( () = expensiveCalculation(props.value), [props.value] ); return ( <div> <h1> The result is: {expensiveResult} </h1> </div> ); }; useMemo
  73. Erik Rasmussen – @erikras React Solid export const Result =

    (props) => { const expensiveResult = useMemo( () = expensiveCalculation(props.value), [props.value] ); return ( <div> <h1> The result is: {expensiveResult} </h1> </div> ); }; useMemo export const Result = (props) => { const expensiveResult = expensiveCalculation(props.value); return ( <div> <h1> The result is: {expensiveResult} </h1> </div> ); }; FOOTGUN #3: Only use signals in JSX. Never "get" their value before the JSX.
  74. Erik Rasmussen – @erikras React Solid export const Result =

    (props) => { const expensiveResult = useMemo( () = expensiveCalculation(props.value), [props.value] ); return ( <div> <h1> The result is: {expensiveResult} </h1> </div> ); }; useMemo export const Result = (props) => { const expensiveResult = () => expensiveCalculation(props.value); return ( <div> <h1> The result is: {expensiveResult()} </h1> </div> ); };
  75. Erik Rasmussen – @erikras React Solid export const Result =

    (props) => { const expensiveResult = useMemo( () = expensiveCalculation(props.value), [props.value] ); return ( <div> <h1> The result is: {expensiveResult} </h1> </div> ); }; useMemo export const Result = (props) => { const expensiveResult = () = expensiveCalculation(props.value); return ( <div> <h1>Result: {expensiveResult()}</h1> <h1>Result: {expensiveResult()}</h1> <h1>Result: {expensiveResult()}</h1> </div> ); };
  76. Erik Rasmussen – @erikras React Solid export const Result =

    (props) => { const expensiveResult = useMemo( () = expensiveCalculation(props.value), [props.value] ); return ( <div> <h1> The result is: {expensiveResult} </h1> </div> ); }; useMemo export const Result = (props) => { const expensiveResult = createMemo( () => expensiveCalculation(props.value) ); return ( <div> <h1>Result: {expensiveResult()}</h1> <h1>Result: {expensiveResult()}</h1> <h1>Result: {expensiveResult()}</h1> </div> ); };
  77. Erik Rasmussen – @erikras React Solid export const Result =

    (props) => { const expensiveResult = useMemo( () = expensiveCalculation(props.value), [props.value] ); return ( <div> <h1> The result is: {expensiveResult} </h1> </div> ); }; useMemo export const Result = (props) => { const expensiveResult = createMemo( () => expensiveCalculation(props.value), [props.value] ); return ( <div> <h1>Result: {expensiveResult()}</h1> <h1>Result: {expensiveResult()}</h1> <h1>Result: {expensiveResult()}</h1> </div> ); };
  78. Erik Rasmussen – @erikras React Solid export const Result =

    (props) => { const expensiveResult = useMemo( () = expensiveCalculation(props.value), [props.value] ); return ( <div> <h1> The result is: {expensiveResult} </h1> </div> ); }; useMemo export const Result = (props) => { const expensiveResult = createMemo( () => expensiveCalculation(props.value) ); return ( <div> <h1>Result: {expensiveResult()}</h1> <h1>Result: {expensiveResult()}</h1> <h1>Result: {expensiveResult()}</h1> </div> ); }; NO DEPENDENCY ARRAY NEEDED!!
  79. Erik Rasmussen – @erikras React Solid export const LoginButton =

    (props) => { return ( <div> {props.loggedIn ? ( <button onClick={() = props.logout()}> Logout </button> ) : ( <button onClick={() = props.login()}> Login </button> )} </div> ); }; <Show/> export const LoginButton = (props) => { return ( <div> {props.loggedIn ? ( <button onClick={() = props.logout()}> Logout </button> ) : ( <button onClick={() = props.login()}> Login </button> )} </div> ); };
  80. Erik Rasmussen – @erikras React Solid export const LoginButton =

    (props) => { return ( <div> {props.loggedIn ? ( <button onClick={() = props.logout()}> Logout </button> ) : ( <button onClick={() = props.login()}> Login </button> )} </div> ); }; <Show/> export const LoginButton = (props) => { return ( <div> {props.loggedIn ? ( <button onClick={() = props.logout()}> Logout </button> ) : ( <button onClick={() = props.login()}> Login </button> )} </div> ); };
  81. Erik Rasmussen – @erikras React Solid export const LoginButton =

    (props) => { return ( <div> {props.loggedIn ? ( <button onClick={() = props.logout()}> Logout </button> ) : ( <button onClick={() = props.login()}> Login </button> )} </div> ); }; <Show/> export const LoginButton = (props) => { return ( <div> props.loggedIn <button onClick={() = props.logout()}> Logout </button> <button onClick={() = props.login()}> Login </button> </div> ); };
  82. Erik Rasmussen – @erikras React Solid export const LoginButton =

    (props) => { return ( <div> {props.loggedIn ? ( <button onClick={() = props.logout()}> Logout </button> ) : ( <button onClick={() = props.login()}> Login </button> )} </div> ); }; <Show/> export const LoginButton = (props) => { return ( <div> <Show when={props.loggedIn}> <button onClick={() = props.logout()}> Logout </button> </Show> <button onClick={() = props.login()}> Login </button> </div> ); };
  83. Erik Rasmussen – @erikras React Solid export const LoginButton =

    (props) => { return ( <div> {props.loggedIn ? ( <button onClick={() = props.logout()}> Logout </button> ) : ( <button onClick={() = props.login()}> Login </button> )} </div> ); }; <Show/> export const LoginButton = (props) => { return ( <div> <Show when={props.loggedIn} fallback={ <button onClick={() = props.login()}> Login </button> } > <button onClick={() = props.logout()}> Logout </button> </Show> </div> ); };
  84. Erik Rasmussen – @erikras React Solid export const Results =

    (props) => { return ( <div> {props.status = "pending" ? ( <Spinner /> ) : props.status = "loaded" ? ( <Items items={props.items} /> ) : ( <Error error={props.error} /> )} </div> ); }; <Switch/> / <Match/> export const Results = (props) => { return ( <div> {props.status = "pending" ? ( <Spinner /> ) : props.status = "loaded" ? ( <Items items={props.items} /> ) : ( <Error error={props.error} /> )} </div> ); };
  85. Erik Rasmussen – @erikras React Solid export const Results =

    (props) => { return ( <div> {props.status = "pending" ? ( <Spinner /> ) : props.status = "loaded" ? ( <Items items={props.items} /> ) : ( <Error error={props.error} /> )} </div> ); }; <Switch/> / <Match/> export const Results = (props) => { return ( <div> {props.status = "pending" ? ( <Spinner /> ) : props.status = "loaded" ? ( <Items items={props.items} /> ) : ( <Error error={props.error} /> )} </div> ); };
  86. Erik Rasmussen – @erikras React Solid export const Results =

    (props) => { return ( <div> {props.status = "pending" ? ( <Spinner /> ) : props.status = "loaded" ? ( <Items items={props.items} /> ) : ( <Error error={props.error} /> )} </div> ); }; <Switch/> / <Match/> export const Results = (props) => { return ( <div> <Switch> <Match when={props.status = "pending"}> <Spinner /> </Match> props.status === "loaded" ? ( <Items items={props.items} /> ) : ( <Error error={props.error} /> )} </Switch> </div> ); };
  87. Erik Rasmussen – @erikras React Solid export const Results =

    (props) => { return ( <div> {props.status = "pending" ? ( <Spinner /> ) : props.status = "loaded" ? ( <Items items={props.items} /> ) : ( <Error error={props.error} /> )} </div> ); }; <Switch/> / <Match/> export const Results = (props) => { return ( <div> <Switch> <Match when={props.status = "pending"}> <Spinner /> </Match> <Match when={props.status = "loaded"}> <Items items={props.items} /> </Match> <Error error={props.error} /> )} </Switch> </div> ); };
  88. Erik Rasmussen – @erikras React Solid export const Results =

    (props) => { return ( <div> {props.status = "pending" ? ( <Spinner /> ) : props.status = "loaded" ? ( <Items items={props.items} /> ) : ( <Error error={props.error} /> )} </div> ); }; <Switch/> / <Match/> export const Results = (props) => { return ( <div> <Switch fallback={<Error error={props.error} />}> <Match when={props.status = "pending"}> <Spinner /> </Match> <Match when={props.status = "loaded"}> <Items items={props.items} /> </Match> </Switch> </div> ); };
  89. export const ItemList = (props) => { return ( <div>

    {props.items.map( (item) = ( <div> {item.name} </div> ) )} </div> ); }; Erik Rasmussen – @erikras React Solid <For/> export const ItemList = (props) => { return ( <div> {props.items.map( (item) = ( <div> {item.name} </div> ) )} </div> ); };
  90. export const ItemList = (props) => { return ( <div>

    {props.items.map( (item) = ( <div> {item.name} </div> ) )} </div> ); }; Erik Rasmussen – @erikras React Solid <For/> export const ItemList = (props) => { return ( <div> {props.items.map( (item) = ( <div> {item.name} </div> ) )} </div> ); };
  91. export const ItemList = (props) => { return ( <div>

    {props.items.map( (item) = ( <div key={item.id}> {item.name} </div> ) )} </div> ); }; Erik Rasmussen – @erikras React Solid <For/> export const ItemList = (props) => { return ( <div> {props.items.map( (item) = ( <div> {item.name} </div> ) )} </div> ); };
  92. export const ItemList = (props) => { return ( <div>

    {props.items.map( (item) = ( <div key={item.id}> {item.name} </div> ) )} </div> ); }; Erik Rasmussen – @erikras React Solid <For/> export const ItemList = (props) => { return ( <div> <For each={props.items}> {(item) = ( <div> {item.name} </div> )} </For> </div> ); }; NO KEY PROP NEEDED!!
  93. class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state =

    { hasError: false }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, info) { logError(error, info.componentStack); } render() { if (this.state.hasError) { return this.props.fallback; } return this.props.children; } } Erik Rasmussen – @erikras React Solid <ErrorBoundary/>
  94. class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state =

    { hasError: false }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, info) { logError(error, info.componentStack); } render() { if (this.state.hasError) { return this.props.fallback; } return this.props.children; } } Erik Rasmussen – @erikras React Solid <ErrorBoundary/> export const App = () => { return ( <div> <ErrorBoundary fallback={(error) = ( <PrettyError error={error} /> )} > <ComponentThatMayThrow /> </ErrorBoundary> </div> ); }; 🙄
  95. Erik Rasmussen – @erikras React Solid style prop export const

    Text = () => { return ( <div style={{ fontWeight: "bold", margin: 15, maxHeight: "90vh", }} > Stylin'! </div> ); }; export const Text = () => { return ( <div style={{ fontWeight: "bold", margin: 15, maxHeight: "90vh", }} > Stylin'! </div> ); };
  96. Erik Rasmussen – @erikras React Solid style prop export const

    Text = () => { return ( <div style={{ fontWeight: "bold", margin: 15, maxHeight: "90vh", }} > Stylin'! </div> ); }; export const Text = () => { return ( <div style={{ fontWeight: "bold", margin: 15, maxHeight: "90vh", }} > Stylin'! </div> ); };
  97. Erik Rasmussen – @erikras React Solid style prop export const

    Text = () => { return ( <div style={{ fontWeight: "bold", margin: 15, maxHeight: "90vh", }} > Stylin'! </div> ); }; export const Text = () => { return ( <div style={{ "font-weight": "bold", margin: "15px", "max-height": "90vh", }} > Stylin'! </div> ); };
  98. Erik Rasmussen – @erikras React Solid class prop export const

    Table = () => { return ( <div> <div className="row"> <div className="column">React</div> <div className="column">Awesome</div> </div> <div className="row"> <div className="column">Solid</div> <div className="column">Also Awesome</div> </div> </div> ); }; export const Table = () => { return ( <div> <div className="row"> <div className="column">React</div> <div className="column">Awesome</div> </div> <div className="row"> <div className="column">Solid</div> <div className="column">Also Awesome</div> </div> </div> ); };
  99. Erik Rasmussen – @erikras React Solid class prop export const

    Table = () => { return ( <div> <div className="row"> <div className="column">React</div> <div className="column">Awesome</div> </div> <div className="row"> <div className="column">Solid</div> <div className="column">Also Awesome</div> </div> </div> ); }; export const Table = () => { return ( <div> <div className="row"> <div className="column">React</div> <div className="column">Awesome</div> </div> <div className="row"> <div className="column">Solid</div> <div className="column">Also Awesome</div> </div> </div> ); };
  100. Erik Rasmussen – @erikras React Solid class prop export const

    Table = () => { return ( <div> <div className="row"> <div className="column">React</div> <div className="column">Awesome</div> </div> <div className="row"> <div className="column">Solid</div> <div className="column">Also Awesome</div> </div> </div> ); }; export const Table = () => { return ( <div> <div class="row"> <div class="column">React</div> <div class="column">Awesome</div> </div> <div class="row"> <div class="column">Solid</div> <div class="column">Also Awesome</div> </div> </div> ); };
  101. Erik Rasmussen – @erikras React Solid classList prop export const

    Item = (props) => { return ( <div className={`item ${ props.selected ? "selected" : "" }`} > {props.item.name} </div> ); }; 🤮
  102. Erik Rasmussen – @erikras React Solid classList prop import cx

    from "classnames"; export const Item = (props) => { return ( <div className={cx("item", { selected: props.selected, })} > {props.item.name} </div> ); };
  103. Erik Rasmussen – @erikras React Solid classList prop import cx

    from "classnames"; export const Item = (props) => { return ( <div className={cx("item", { selected: props.selected, })} > {props.item.name} </div> ); };
  104. Erik Rasmussen – @erikras React Solid classList prop import cx

    from "classnames"; export const Item = (props) => { return ( <div className={cx("item", { selected: props.selected, })} > {props.item.name} </div> ); };
  105. Erik Rasmussen – @erikras React Solid classList prop import cx

    from "classnames"; export const Item = (props) => { return ( <div className={cx("item", { selected: props.selected, })} > {props.item.name} </div> ); };
  106. Erik Rasmussen – @erikras React Solid classList prop import cx

    from "classnames"; export const Item = (props) => { return ( <div className={cx("item", { selected: props.selected, })} > {props.item.name} </div> ); }; export const Item = (props) => { return ( <div class="item" classList={{ selected: props.selected, }} > {props.item.name} </div> ); };
  107. Erik Rasmussen – @erikras React Solid classList prop export const

    Item = (props) => { return ( <div className={`item ${ props.selected ? "selected" : "" }`} > {props.item.name} </div> ); }; export const Item = (props) => { return ( <div class="item" classList={{ selected: props.selected, }} > {props.item.name} </div> ); }; 🤮 😎
  108. Erik Rasmussen – @erikras React Solid Lifecycle Methods export const

    MyComponent = (props) => { useEffect(() => { console.log("MyComponent mounted"); return () => { console.log("MyComponent unmounted"); }; }); return <div>Hello, {props.name}!</div>; };
  109. Erik Rasmussen – @erikras React Solid Lifecycle Methods export const

    MyComponent = (props) => { useEffect(() => { console.log("MyComponent mounted"); return () => { console.log("MyComponent unmounted"); }; }, []); return <div>Hello, {props.name}!</div>; }; 🙄
  110. Erik Rasmussen – @erikras React Solid Lifecycle Methods export const

    MyComponent = (props) => { useEffect(() => { console.log("MyComponent mounted"); return () => { console.log("MyComponent unmounted"); }; }, []); return <div>Hello, {props.name}!</div>; }; export const MyComponent = (props) => { return <div>Hello, {props.name}!</div>; };
  111. Erik Rasmussen – @erikras React Solid Lifecycle Methods export const

    MyComponent = (props) => { useEffect(() => { console.log("MyComponent mounted"); return () => { console.log("MyComponent unmounted"); }; }, []); return <div>Hello, {props.name}!</div>; }; export const MyComponent = (props) => { onMount(() => { console.log("MyComponent mounted"); }); return ( <div>Hello, {props.name}!</div> ); };
  112. Erik Rasmussen – @erikras React Solid Lifecycle Methods export const

    MyComponent = (props) => { useEffect(() => { console.log("MyComponent mounted"); return () => { console.log("MyComponent unmounted"); }; }, []); return <div>Hello, {props.name}!</div>; }; export const MyComponent = (props) => { onMount(() => { console.log("MyComponent mounted"); }); onCleanup(() => { console.log("MyComponent unmounted"); }); return ( <div>Hello, {props.name}!</div> ); }; FOOTGUN #2: The component function is only called once! NO DEPENDENCY ARRAY NEEDED!!
  113. Erik Rasmussen – @erikras • Context API with createContext() •

    Lazy components • Suspense • useQuery-like Resources with useResource() • immer-like mutation API with produce() • Next.js-like application framework called SolidStart • Routing, SSR, SSG, etc. Solid Familiar
  114. Erik Rasmussen – @erikras • Nested Reactivity with createStore() •

    Batched updates with batch() • Directives with use: props • Google "solid fi nal form" Solid Less Familiar <input name="firstName" placeholder="First Name" use:field />;
  115. Erik Rasmussen – @erikras Footgun Recap 1. Signal values are

    getter functions! 2. The Component function is called only once! 3. Only call signal getters in JSX (or other derived signals).
 Never call getter before return. 4. Never destructure props! 5. The Component function is called only once! 6. The Component function is called only once! <div>{value}</div> <div>{value()}</div> ❌ ✅
  116. Erik Rasmussen – @erikras React Solid React's kryptonite is re-rendering.

    – Erik Rasmussen @erikras React's superpower is re-rendering.
  117. Erik Rasmussen – @erikras React Solid React's kryptonite is re-rendering.

    – Erik Rasmussen @erikras React's superpower is re-rendering.
  118. Erik Rasmussen – @erikras React Solid The JS Framework Benchmark

    compares browser performance across a wide range of tests. Lower is better.