<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[CoLoop Engineering Blog]]></title><description><![CDATA[CoLoop Engineering Blog]]></description><link>https://eng.coloop.ai</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1769201039900/c1f1dee2-c81c-4788-b586-7f1210f2d0a2.png</url><title>CoLoop Engineering Blog</title><link>https://eng.coloop.ai</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 22 May 2026 03:44:17 GMT</lastBuildDate><atom:link href="https://eng.coloop.ai/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[React Slots: Dynamic Sidebars and Headers Without the Mess]]></title><description><![CDATA[The Problem
You have a layout with a sidebar. Different pages need different sidebar content. The obvious solutions all have tradeoffs:
Prop drilling: Pass sidebar content up through every layer. Verbose, brittle.
Global state: Store sidebar config i...]]></description><link>https://eng.coloop.ai/react-slots-dynamic-sidebars-and-headers-without-the-mess</link><guid isPermaLink="true">https://eng.coloop.ai/react-slots-dynamic-sidebars-and-headers-without-the-mess</guid><category><![CDATA[React]]></category><category><![CDATA[ReactHooks]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[frontend]]></category><dc:creator><![CDATA[Adrien Wald]]></dc:creator><pubDate>Wed, 28 Jan 2026 14:16:22 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-the-problem">The Problem</h2>
<p>You have a layout with a sidebar. Different pages need different sidebar content. The obvious solutions all have tradeoffs:</p>
<p><strong>Prop drilling</strong>: Pass sidebar content up through every layer. Verbose, brittle.</p>
<p><strong>Global state</strong>: Store sidebar config in Redux/Zustand. Now your UI is in a store.</p>
<p><strong>Render props</strong>: <code>&lt;Layout sidebar={&lt;Filters /&gt;}&gt;</code>. Works until you need sidebar content that depends on state defined inside the page.</p>
<p>That last point is the killer. Your filters component needs access to state that lives deep in your page component. Now what?</p>
<h2 id="heading-the-solution">The Solution</h2>
<p>A slot is a named portal target discovered at runtime via React context.</p>
<pre><code class="lang-tsx">import { createContext, useContext, useState, PropsWithChildren } from 'react'
import { createPortal } from 'react-dom'

type SlotState = [
  HTMLDivElement | null,
  React.Dispatch&lt;React.SetStateAction&lt;HTMLDivElement | null&gt;&gt;,
]

export function createSlot(name: string) {
  const Context = createContext&lt;SlotState | null&gt;(null)

  function useSlot() {
    const ctx = useContext(Context)
    if (!ctx) {
      throw new Error(`${name} must be used within ${name}.Provider`)
    }
    return ctx
  }

  function Provider({ children }: PropsWithChildren) {
    const slotState = useState&lt;HTMLDivElement | null&gt;(null)
    return &lt;Context.Provider value={slotState}&gt;{children}&lt;/Context.Provider&gt;
  }

  function Slot(props: React.HTMLAttributes&lt;HTMLDivElement&gt;) {
    const [, setSlot] = useSlot()
    return &lt;div {...props} ref={setSlot} /&gt;
  }

  function Portal({ children }: PropsWithChildren) {
    const [slot] = useSlot()
    return slot ? createPortal(children, slot) : null
  }

  return { Provider, Slot, Portal }
}
</code></pre>
<h2 id="heading-usage">Usage</h2>
<pre><code class="lang-tsx">const Sidebar = createSlot('Sidebar')

function Layout({ children }: PropsWithChildren) {
  return (
    &lt;Sidebar.Provider&gt;
      &lt;div className="flex"&gt;
        &lt;aside&gt;
          &lt;Sidebar.Slot /&gt;
        &lt;/aside&gt;
        &lt;main&gt;{children}&lt;/main&gt;
      &lt;/div&gt;
    &lt;/Sidebar.Provider&gt;
  )
}

function SearchPage() {
  const [filters, setFilters] = useState({ date: 'any', type: 'all' })
  const results = useSearch(filters)

  return (
    &lt;&gt;
      &lt;ResultsList results={results} /&gt;

      &lt;Sidebar.Portal&gt;
        &lt;Filters value={filters} onChange={setFilters} /&gt;
        &lt;ResultCount count={results.length} /&gt;
      &lt;/Sidebar.Portal&gt;
    &lt;/&gt;
  )
}
</code></pre>
<p>The filters live in the sidebar visually, but in <code>SearchPage</code> logically. State stays colocated with the component that uses it.</p>
<h2 id="heading-why-this-works">Why This Works</h2>
<p>React has two hierarchies: the component tree (data flow) and the DOM tree (visual layout). They're usually the same. Portals let you separate them.</p>
<p>Standard portals target fixed DOM nodes like <code>document.body</code>. This pattern targets a dynamic node discovered via context. The slot registers itself with a ref. The portal finds it through the same context.</p>
<p>Result: components inject content into arbitrary layout positions while preserving normal React data flow. Context, state, handlers — everything works as expected.</p>
<h2 id="heading-when-to-use-this">When to Use This</h2>
<ul>
<li><p>Sidebars with page-specific content</p>
</li>
<li><p>Header actions that depend on page state</p>
</li>
<li><p>Toolbars that change based on selection</p>
</li>
<li><p>Any layout where content source and content location should be decoupled</p>
</li>
</ul>
<h2 id="heading-when-not-to">When Not To</h2>
<p>If your sidebar content doesn't need state from inside the page, simpler patterns work fine. Render props or composition handle static content without the indirection.</p>
]]></content:encoded></item><item><title><![CDATA[State is a Record of the Past, Not a Claim About the Present]]></title><description><![CDATA[One of the most common React mistakes I see is using useEffect to keep two pieces of state in sync. It seems intuitive, but it introduces a subtle bug — and more importantly, it reveals a misunderstanding about what state actually represents.
The Pro...]]></description><link>https://eng.coloop.ai/state-is-a-record-of-the-past-not-a-claim-about-the-present</link><guid isPermaLink="true">https://eng.coloop.ai/state-is-a-record-of-the-past-not-a-claim-about-the-present</guid><category><![CDATA[React]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[Front-end Development]]></category><category><![CDATA[ReactHooks]]></category><dc:creator><![CDATA[Adrien Wald]]></dc:creator><pubDate>Fri, 23 Jan 2026 20:26:27 GMT</pubDate><content:encoded><![CDATA[<p>One of the most common React mistakes I see is using <code>useEffect</code> to keep two pieces of state in sync. It seems intuitive, but it introduces a subtle bug — and more importantly, it reveals a misunderstanding about what state actually represents.</p>
<h2 id="heading-the-problem">The Problem</h2>
<p>Imagine you have a list of items and a selected item ID. When items change, you need to clear the selection if the selected item no longer exists.</p>
<p>Here's the instinctive (but wrong) approach:</p>
<pre><code class="lang-tsx">function ItemList() {
  const [selectedId, setSelectedId] = useState&lt;string | null&gt;(null)
  const items = useItems()

  useEffect(() =&gt; {
    if (selectedId !== null &amp;&amp; !items.some((item) =&gt; item.id === selectedId)) {
      setSelectedId(null)
    }
  }, [items, selectedId])

  return &lt;List items={items} selectedId={selectedId} /&gt;
}
</code></pre>
<p>This looks reasonable, but there's a hidden problem: <strong>for one render,</strong> <code>selectedId</code> points to an item that doesn't exist.</p>
<p>React renders with stale state, <em>then</em> the effect runs and fixes it. During that intermediate render, any code that assumes <code>selectedId</code> is valid will break.</p>
<p>But there's a deeper issue here — this code misunderstands what state is for.</p>
<h2 id="heading-the-mental-shift">The Mental Shift</h2>
<p>When you call <code>setSelectedId("abc")</code>, you're not declaring "item abc is selected." You're recording an event: <strong>"the user selected item abc."</strong></p>
<p>State is a record of what happened. It's historical. It doesn't make claims about whether that selection is still valid — that's a separate concern.</p>
<p>This reframing changes everything. Watch what happens when we rename the variable to reflect what it actually holds:</p>
<pre><code class="lang-tsx">function ItemList() {
  const [lastSelectedId, setLastSelectedId] = useState&lt;string | null&gt;(null)
  const items = useItems()

  const selectedId = useMemo(
    () =&gt; items.some((item) =&gt; item.id === lastSelectedId) ? lastSelectedId : null,
    [items, lastSelectedId],
  )

  return &lt;List items={items} selectedId={selectedId} /&gt;
}
</code></pre>
<p>Now the code reads honestly:</p>
<ul>
<li><p><code>lastSelectedId</code> — the last ID the user selected (a fact about the past)</p>
</li>
<li><p><code>selectedId</code> — the currently valid selection (derived from present reality)</p>
</li>
</ul>
<p>There's no <code>useEffect</code>. No sync. No intermediate broken render. The derivation happens synchronously during render, so <code>selectedId</code> is <strong>always</strong> consistent with <code>items</code>.</p>
<h2 id="heading-the-principle">The Principle</h2>
<p><strong>State records what happened. Derived values describe what's true now.</strong></p>
<p>When you try to store "what's true now" directly in state, you end up fighting to keep it updated — hence the <code>useEffect</code> trap. But when you store the raw historical fact and derive current truth from it, everything stays in sync automatically.</p>
<h2 id="heading-a-reusable-hook">A Reusable Hook</h2>
<p>This pattern comes up often enough that it's worth extracting:</p>
<pre><code class="lang-tsx">function useSelection&lt;TItem, TKey extends keyof TItem&gt;(
  items: TItem[],
  identifierKey: TKey,
): [TItem[TKey] | null, (id: TItem[TKey] | null) =&gt; void] {
  const [lastSelectedId, setLastSelectedId] = useState&lt;TItem[TKey] | null&gt;(null)

  const selectedId = useMemo(
    () =&gt; items.some((item) =&gt; item[identifierKey] === lastSelectedId) ? lastSelectedId : null,
    [items, identifierKey, lastSelectedId],
  )

  return [selectedId, setLastSelectedId]
}
</code></pre>
<p>Usage is clean:</p>
<pre><code class="lang-tsx">function ItemList() {
  const items = useItems()
  const [selectedId, setSelectedId] = useSelection(items, 'id')

  return &lt;List items={items} selectedId={selectedId} /&gt;
}
</code></pre>
<p>The hook encapsulates the pattern: store the user's action, derive the valid state. Consumers get a <code>selectedId</code> that's always safe to use.</p>
<h2 id="heading-takeaway">Takeaway</h2>
<p>Next time you reach for <code>useEffect</code> to "fix" state based on other state, pause. Ask yourself: <em>am I storing a fact about the past, or am I trying to store current truth?</em></p>
<p>Store the past. Derive the present.</p>
]]></content:encoded></item></channel></rss>