teaful icon indicating copy to clipboard operation
teaful copied to clipboard

custom hook like react query

Open yathink3 opened this issue 3 years ago • 8 comments

can we create custom hook like react query or redux rtk query @aralroca

yathink3 avatar Nov 13 '21 16:11 yathink3

Something like this?

const { isLoading, error, data } = useQuery('repoData', () =>
     fetch('https://api.github.com/repos/tannerlinsley/react-query').then(res =>
       res.json()
     )
   )

aralroca avatar Nov 13 '21 17:11 aralroca

yes , but same time we need to control over values on store,

i like redux and rtk query , but i had problem like we cant control over rtk query

yathink3 avatar Nov 13 '21 17:11 yathink3

I will think of an alternative to see if it fits. Any implementation proposal will be welcome 😊

aralroca avatar Nov 13 '21 17:11 aralroca

For whatever it's worth, I futzed around and made something vaguely like it:

import createStore from "teaful";

// STORE
export const { useStore, getStore, withStore } = createStore({
  data: null,
  loading: true,
  error: null
})

// ACTIONS
export const refresh = () => Promise.resolve()
  .then(() => getStore.loading()[1](true))
  .then(() => fetch('https://picsum.photos/v2/list'))
  .then(x => x.json())
  .then(data => getStore.data()[1](data))
  .catch(error => getStore.error()[1](error))
  .finally(() => getStore.loading()[1](false));

Then in the component consuming it:

import { useStore, refresh } from './store'

export default function App() {
  const [data] = useStore.data()
  const [loading] = useStore.loading()
  const [error] = useStore.error()
  return (
    <>
      <h1>Photo!</h1>
      {loading && <span>LOADING</span>}
      {!loading && !error && <pre>{JSON.stringify(data[10], null, 2)}</pre>}
      <button onClick={() => refresh()}>Refresh picture</button>
    </>
  );
}

And it seems to work about like that.

MikeMcElroy avatar Nov 30 '21 20:11 MikeMcElroy

Granted, this is my first time playing with Teaful, so I'm probably doing a lot wrong, but it seems nicely packaged up.

MikeMcElroy avatar Nov 30 '21 20:11 MikeMcElroy

Thanks @MikeMcElroy! Great implementation 😊

@yathink3 To use a method similar to useQuery for more queries is possible with something like this:

const { useStore } = createStore(initialStore);

function useQuery(key, query) {
  const [field, setField] = useStore[key]()

  useEffect(() => {
    if (field) return
    setField({ isLoading: true })
    query()
      .then(data => setField(s => ({ ...s, data })))
      .catch((error) => setField(s => ({ ...s, error })))
      .finally(() => setField(s => ({ ...s, isLoading: false })))
  }, [])
 
  return field || { isLoading: true }
}

And then inside a components:

const { isLoading, error, data } = useQuery('repoData', () =>
     fetch('https://picsum.photos/v2/list').then(res =>
       res.json()
     )
   )

or after the query:

const [{ isLoading, error, data }] =  useStore.repoData()

or:

const [data] =  useStore.repoData.data()

If you want the useQuery to be inside each createStore:

const { useQuery } = createStore() // Something like this

It can be added as an extra without increasing the size of the library (in the case you do not want this extra).

About extras:

https://github.com/teafuljs/teaful/blob/09b78a04d14e51f827d1e05bf0d184079a7f331e/README.md#addons-and-extras- (Documentation I am updating here)

aralroca avatar Nov 30 '21 21:11 aralroca

Note: It would be nice to make an integration with Suspense.

<Suspense fallback="Loading...">
  <ComponentThatUseQuery />
<Suspense/>

ComponentThatUseQuery:

const [data, setData] = useQuery('repoData', () =>
     fetch('https://picsum.photos/v2/list').then(res =>
       res.json()
     )
   )

https://reactjs.org/docs/concurrent-mode-suspense.html

aralroca avatar Dec 03 '21 12:12 aralroca

ya i got it, now teaful is 🚀🚀 with devtools

yathink3 avatar Dec 03 '21 17:12 yathink3