Docs
Selectors

Selectors

Selectors provide a way to create derived states. They can be created with the same atom | create function. There is one difference: selectors should have a get method that will run whenever any of the states they are subscribed to changes.

Advantages

  • Selectors are re-rendered only when any of the atom's they are subscribed to updates their state.
  • They can return promises
import { create } from 'atomic-state'
 
const todos = create({
  key: 'todos',
  default: []
})
 
const completedTodosState = create({
  key: 'completedTodos',
  get({ get }) {
    // This selector will re-render only when 'todos' changes.
    // You can check that by adding a console.log :)
 
    const todosState = get(todos)
 
    return todosState.filter((todo) => todo.completed)
  }
})
 
const useCompletedTodos = completedTodosState.useValue
 
function CompletedTodos() {
  // Type is inferred here
  const completedTodos = useCompletedTodos()
 
  return <p>Completed todos: {completedTodos.length}</p>
}
💡

Because selectors depend on other atoms' states, their state cannot be set manually. This also means that actions don't work inside them

They can also return promises:

@/states/index.jsx
import { create } from 'atomic-state'
 
const text = create({
  key: 'text',
  default: ''
})
 
export const searchResults = create({
  key: 'searchResults',
  default: [],
  async get({ get }) {
    const textState = get(text)
 
    return fetch('/search?q=' + textState).then((res) => res.json())
  }
})
 
export const useSearchResults = searchResults.useValue
💡

Note that in this case the result of the selector is a Promise, so it will not be available while it's resolving. In that case, default is required. The return type will be inferred from it as well.

They can also subscribe to other selectors:

import { create } from 'atomic-state'
 
import { searchResults } from '@/states'
 
const infoState = atom({
  key: 'info',
  default: {
    name: '',
    searchResults: []
  },
  async get({ get }) {
    const searchResultsValue = await get(searchResults)
 
    return {
      name: '',
      searchResults
    }
  }
})

In this example, we are using async/await because the current state of searchResultsState could still be a Promise

Last updated on August 8, 2024