Skip to content

feat: add value getter to the store selctor for easy access to the selected slice of the state#329

Open
fredericbahr wants to merge 1 commit into
TanStack:mainfrom
fredericbahr:feat-add-value-getter-to-store-selctor
Open

feat: add value getter to the store selctor for easy access to the selected slice of the state#329
fredericbahr wants to merge 1 commit into
TanStack:mainfrom
fredericbahr:feat-add-value-getter-to-store-selctor

Conversation

@fredericbahr
Copy link
Copy Markdown

@fredericbahr fredericbahr commented May 16, 2026

🎯 Changes

Added value-setter in the Lit TanstackStoreSelector for easy access to lifecycle-aware fine-grained reactivity.
This aligns with the react-hook which also returns the value directly: const count = useSelector(counterStore, (state) => state.count)

Additonally this helps using @tanstack/lit-table internally for the Subscribe function, which im currently trying to reimplement (TanStack/table#6267).

Added

  • Added TanstackStoreSelctor.value getter for direct access to selected state

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • New Features

    • Added a public value getter to access the currently selected store value directly.
  • Documentation

    • Updated quick-start examples to demonstrate selector-driven rerenders and direct store value access patterns with clearer template output.
  • Tests

    • Added a test verifying selector-driven updates reflect in rendered output.
  • Chores

    • Updated release notes/changeset to document the minor version bump.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 16, 2026

📝 Walkthrough

Walkthrough

This PR adds a public value getter to TanStackStoreSelector (exposes the last selected value), expands JSDoc with usage examples, adds a test verifying rendered updates when the selector value changes, updates the quick-start docs to demonstrate .value usage, and includes a changeset for a minor release.

Changes

TanStackStoreSelector value getter

Layer / File(s) Summary
TanStackStoreSelector.value getter and JSDoc
packages/lit-store/src/tan-stack-store-selector.ts
Added comprehensive JSDoc describing subscription and rerender semantics, and a public value getter that returns the last selected value or undefined.
Selector test suite and value getter test
packages/lit-store/tests/selector.test.ts
Removed async modifier from the top-level describe and added a vitest test that verifies a component using TanStackStoreSelector updates its rendered output when the store state changes.
Quick-start documentation and examples
docs/framework/lit/quick-start.md
Updated quick-start to explain two usage patterns: selector-driven rerenders and direct .value access. Revised AnimalDisplay example to render counter.value and also show store.state[animal].
Changeset entry
.changeset/light-cobras-live.md
Added/updated changeset declaring a minor release and noting the added value getter on TanStackStoreSelector.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A tiny getter, tucked away neat,
Watches selections and keeps them sweet,
Templates sip .value with delight,
Tests clap paws when the UI gets it right,
Docs tell the tale in lines concise and neat.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding a value getter to the store selector for easy access to the selected state slice.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description follows the required template structure with all key sections completed: Changes section explaining the addition and motivation, completed checklist items, and correct Release Impact selection.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/framework/lit/quick-start.md`:
- Line 8: Update the opening line to be a complete sentence by expanding the
fragment to something like "The `TanStackStoreSelector` can be used in two
ways." Locate the line referencing `TanStackStoreSelector` in the quick-start
content and replace the fragment with the full sentence form so it reads
grammatically complete and clear.

In `@packages/lit-store/src/tan-stack-store-selector.ts`:
- Line 31: Update the JSDoc examples for TanStackStoreSelector to use correct,
copy-pastable symbols and remove stray formatting: replace the invalid reference
`TanStackStoreAtom` with the intended class/name (TanStackStoreSelector) and
remove backticks around instance property examples like `#name` so the snippet
shows valid JS/TS usage (e.g., const name = new TanStackStoreSelector(...); or
selector.name) in both example blocks that reference the selector; ensure the
example code compiles and matches the actual API surface of
TanStackStoreSelector.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 07a835dd-8b5b-4fd3-b7fd-c01ba7caebc6

📥 Commits

Reviewing files that changed from the base of the PR and between 09139b1 and e548931.

📒 Files selected for processing (3)
  • docs/framework/lit/quick-start.md
  • packages/lit-store/src/tan-stack-store-selector.ts
  • packages/lit-store/tests/selector.test.ts

Comment thread docs/framework/lit/quick-start.md Outdated
Comment thread packages/lit-store/src/tan-stack-store-selector.ts Outdated
@fredericbahr fredericbahr force-pushed the feat-add-value-getter-to-store-selctor branch from e548931 to 1c84546 Compare May 16, 2026 17:36
@fredericbahr
Copy link
Copy Markdown
Author

@KevinVandy or @crutchcorn could you perhaps have a look and approve this PR If you find Some spare time?

It is needed to continue to work on a PR in Tanstack/table.

Kind regards.

@crutchcorn
Copy link
Copy Markdown
Member

I don't understand why this is needed or how it pragmatically helps Table. Can you expand on that?

@fredericbahr
Copy link
Copy Markdown
Author

TL;DR

  • Improves DX by removing the need to access store.state separately after defining a selector.
  • Aligns the Lit adapter API with the behavior of the existing framework adapters.
  • Centralizes selection logic inside the controller, reducing duplication and therefore simplifying integrations such as TanStack Table.

Developer Experience

I believe this change improves the developer experience.

Consider the following example:

export const store = createStore({
  dogs: 0,
  cats: 0,
})

export class AnimalDisplay extends LitElement {
  // Subscribes only to `state[animal]`
  counter = new TanStackStoreSelector(
    this,
    () => store,
    (state) => state["dogs"],
  )

  render() {
    return html`
      <div>
        <p>
          Reading directly from store.state:
          ${store.state["dogs"]}
        </p>
      </div>
    `
  }
}

If the requirements later change and the component should display the bird counter instead, there are currently three separate places that need to be updated:

export const store = createStore({
  birds: 0, // update store structure
  cats: 0,
})

export class AnimalDisplay extends LitElement {
  counter = new TanStackStoreSelector(
    this,
    () => store,
    (state) => state["birds"], // update selector
  )

  render() {
    return html`
      <div>
        <p>
          Reading directly from store.state:
          ${store.state["birds"]} // update access to the selected information again
        </p>
      </div>
    `
  }
}

This can technically be mitigated by introducing a private accessor or helper method, but I think the selector itself is the more appropriate abstraction for both selecting and exposing a specific piece of state.

Aligning with other framework adapters

Looking at the other framework adapters, the abstraction already behaves this way by returning the selected value directly and updating it reactively when the store changes:

  1. React’s useStore returns the selected value directly rather than only triggering a rerender.
  2. Vue’s useSelector follows the same pattern.
  3. Angular’s injectSelector abstractions also expose the selected value through the abstraction itself, by calling the a method.
  4. The same principle applies to the Solid adapter.

From that perspective, exposing the selected value directly in the Lit abstraction would make the API more consistent across the ecosystem as currently the lit adapter is the only adapter that requires an additional access to the store.

Usage in Tanstack Table

This also seems beneficial for integrating this adapter into TanStack Table. The subscriber/controller can internally handle state selection and expose only the derived value. For example, in this change:

https://github.com/TanStack/table/pull/6267/changes#diff-b2fe3488ac2c1f109c40e65247eb252a9ccad0dc505c8fb5f0394f70cd3eccd8R221

Using a getter for the selected value simplifies the implementation because the controller becomes fully responsible for evaluating and updating the selection. Without that abstraction, we internally would need to manually retrieve the source state and reapply the selector function, even though that logic has already been handled by the controller.

Please let me know if I’m missing something or if you see it differently. Happy to continue the discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants