use-selector

useSelector hook for computing a state from another state


Keywords
react, hooks, useState, useSelector, state, state-management, recoil
License
MIT
Install
npm install use-selector@3.0.1

Documentation

npm version Build Status

useSelector

useSelector hook for computing a state from another state

  • Usable without external state management libraries
  • Composable utility selectors:
    • selectKey
    • selectProjection
  • Integration with Recoil
    • Native Recoil selectors:
      • keySelector
      • projection
  • Custom selectors (by implementing the Selector interface)
  • Typescript support!

Instal

npm i --save use-selector

Usage

Read only:

const newState = useSelectorValue(() => {
  /* return newState's value here */
}, [dependingState1, dependingState2] /* dependencies */);

Detailed example:

import React, { useState } from 'react';
import { useSelectorValue } from 'use-selector';

function Form() {
  const [title, setTitle] = useState('');
  const [text, setText] = useState('');
  const isFormValid = useSelectorValue(() => title !=== '' && text !== '', [title, text]);

  return (
    <form>
      <input onChange={e => setTitle(e.target.value)} value={title} />
      <input onChange={e => setText(e.target.value)} value={text} />

      <button disabled={isFormValid} />
    </form>
  );
}

export default Form;

Advanced usage

Utility Selectors

import React, { useState } from 'react';
import { selectKey, selectProjection } from 'use-selector';

function Profile() {
  const [user, setUser] = useState({
    info: {
      firstName: 'Jane',
      lastName: 'Doe'
      photo: '/images/jane.png',
      title: 'Director',
    },
    roles: ['ADMIN'],
  });

  // Read only select, changes NOT reflected in 'user'
  const [info, setInfo] = useSelector(selectKey(user, 'info'));
  // info = { firstName, lastName, photo, title }

  // Read/Write select (by passing setParent = setInfo)
  // Changes DO reflect in 'info'
  const [name, setName] = useSelector(
    selectProjection(info, ['firstname', 'lastName'], setInfo)
  )
  // name = { firstName, lastName }

  // ...
}

Recoil

import { atom } from 'recoil';
import { keySelector, projection } from 'use-selector/recoil';

interface User {
  firstName: string,
  lastName: string,
  email: string | null,
}

interface Session {
  user: User,
  expires: Date
}

export const sessionState = atom<Session>({
  key: 'sessionState'
});

// Read/Write user state in sync with session.user
export const userState = keySelector(sessionState, 'user'); // RecoilState<User>

// Read/Write name state in sync with user
export const nameState = projection(userState, ['firstName', 'lastName']);
// RecoilState<{ firstName: string, lastName: string }>

Custom Selector

function mySelector(parent, setParent) {
  return {
    get: () => parent + ' mutated',
    set: ({ get, set }, newValue) => {
      const internalState = get();  // internalState = '${parent} mutated'
      set(newValue + ' set'); // internalState = `${newValue} set`
      setParent(newValue) // parent = newValue, internalState =  `${newValue} set`
    },
    dependencies: [/* dependencies, optional */]
  };
}

License

MIT