Recoil: Using the setter of a (write-only) selector to append to a string atom?

Created on 25 Oct 2020  路  3Comments  路  Source: facebookexperimental/Recoil

I have a search textbox with comma-separated search terms. In order to append a new search term, I'd like to use a selector to avoid re-implementing the append logic. Currently, I use the setter of a selector but since the getter is mandatory, I have to implement it as well. Below you can find the current implementation (simplified). My question: I'm not happy with it since all I need is a write-only selector but I have to implement the get. Do you have a suggestion on how to implement this use-case in a better way?

export const searchStringState = atom<string>({
  key: 'searchStringState',
  default: '',
});

export const searchTermsState = selector<string[]>({
  key: 'searchTermsState',
  get: ({ get }) =>
    get(searchStringState)
      .split(',')
      .filter(Boolean)
      .map((x) => x.trim()),
});

// since I want to call the selector with a string, I have to implement the getter with `searchStringState`,
// otherwise TypeScript would complain that `string` and `string[]` aren't compatible.
export const appendSearchTermState = selector<string>({
  key: 'appendSearchTermState',
  get: ({ get }) => get(searchStringState),
  set: ({ get, set }, newValue) => {
    const currentSearchString = get(searchStringState);
    const currentSearchTerms = get(searchTermsState);

    set(
      searchStringState,
      `${currentSearchString}, ${newValue}`,
    );
  },
});

question

Most helpful comment

Thanks @BenjaBobs! Yup, using simple hooks here is great for constructing an API and there shouldn't be a need for the write-only selector node for this use-case. That helps avoid the overhead of complicating the data-flow graph of atoms/selectors. For more complex API, you could also use useRecoilCallback() which allows reading/writing to dynamically determined atoms/selectors. But, always a good idea to keep it simple if you can.

All 3 comments

I'd just make a generic hook.

export default function useSearchStringApi() {
    const setSearchString = useSetRecoilValue(searchStringState);

    return {
        append: (str: string) => setSearchString(search => search  + ',' + str);
        // can also add other stuff like get value or remove a substring or stuff like that
    }
}

Thanks @BenjaBobs! Yup, using simple hooks here is great for constructing an API and there shouldn't be a need for the write-only selector node for this use-case. That helps avoid the overhead of complicating the data-flow graph of atoms/selectors. For more complex API, you could also use useRecoilCallback() which allows reading/writing to dynamically determined atoms/selectors. But, always a good idea to keep it simple if you can.

Yeah, thanks a lot @BenjaBobs! I've been so focussing on following the recoil way I completely overlooked the obvious way ^^

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Etherum7 picture Etherum7  路  3Comments

yuantongkang picture yuantongkang  路  3Comments

atanasster picture atanasster  路  3Comments

itsMapleLeaf picture itsMapleLeaf  路  4Comments

julienJean99 picture julienJean99  路  3Comments