Main Concepts
The Croods tuple
The main concept of Croods is what it provides you every time you call useCroods
or Fetch
:
const [state, actions] = useCroods({ name: 'images' })
We are following the React hooks pattern of keeping the state
on the first value of the tuple and the action
that changes the state
on the later.
State
state
stores any state related data.
Eg:. Payload returned from fetching/saving/destroying data or API errors.
This object will have the following schema:
state = {
info: null,
list: [],
fetchingInfo: false,
fetchingList: false,
saving: null,
destroying: false,
infoError: null,
listError: null,
saveError: null,
destroyError: null,
}
This piece of state is going to be changing every time you call an action, and when the action resolves, be it a failure or a success.
Actions
The actions
object will have the following structure:
actions = {
fetch: config => query => {...},
save: config => data => {...},
destroy: config => query => {...},
setInfo: data => {...},
setList: data => {...},
resetState: options => void
dangerouslyClearCroodsState: () => void
}
The main 3 actions are: fetch
, save
and destroy
. Those actions give you everything you need for any CRUD operation.
Fetch
If you want to fetch a list or a single item from the database:
<button onClick={fetch()} />
On the above example, when you click the button, a GET
request will be dispatched at ${baseUrl}/images
to GET
a list of images (AKA: index, list or find).
If you want to GET
a single item, you should pass an id:
<button onClick={fetch({ id: 1 })} />
On this example, when you click the button, a GET
request will be dispatched at ${baseUrl}/images/1
to GET
one image (AKA: show or info).
So, keep this in mind:
const fetchItem = fetch({ id: 'truthyValue' })
const fetchList = fetch() // same as { id: 'false/null/undefined' }
You can override this behavior though.
Save
As for the CREATE
and UPDATE
you've got the save
action:
<button onClick={() => save()({ src: 'foo.png' })} />
On the code above, when you click the button, a POST
request will be dispatched at ${baseUrl}/images
to CREATE
an image with data: { "src":"foo.png" }
.
If you want to UPDATE
an item though, you should pass an id:
<button onClick={() => save({ id: 1 })({ src: 'foo.png' })} />
Then you'll be sending a PUT
request at ${baseUrl}/images/1
with data: { "src":"foo.png" }
.
So, if you really want to name your method you can do the following:
const update = save({ id: 'truthyValue' })
const create = save() // same as { id: 'false/null/undefined' }
You can override this behavior though.
Destroy
For the DELETE
method you'll have the destroy
action:
<button onClick={destroy({ id: 1 })} />
This code will send a DELETE
request to ${baseUrl}/images/1
.
The actions will be changing the state on the fly
So that first piece of state will be changing according to the API responses, for instance, when you click the first button <button onClick={fetch()} />
, state.fetchingList
will be true
.
When the request resolves you'll have the images at state.list
and state.fetchingList
will be false
again.
Configuring your requests
Another very important concept is about how and where to configure your requests.
As we've already seen, you can setup project defaults for every request under CroodsProvider
.
Then, on every instance of Croods (useCroods
/Fetch
) you can also setup configuration through an object (for the useCroods
hook) or props (for the Fetch
component).
If you want more specificity though, you can pass any configuration from CroodsProvider
and useCroods/Fetch
into an action's first parameter (config
). This is valid for fetch
, save
and destroy
.
<CroodsProvider afterSuccess={() => console.log('From Provider')}>
<Fetch
afterSuccess={() => console.log('From Fetch')}
name="todos"
render={(list, [_, { destroy }]) => {
return list.map(item => (
<button key={item.id} onClick={() => {
destroy({
id: item.id,
afterSuccess: () => console.log('From the action'),
})()
}}>
Delete
</button>
))
}}
/>
</CroodsProvider>
On the example above, you wouldn't see the From Provider
log because Fetch
is overriding it (for everything underneath the Fetch
itself).
When the component mounts and the Fetch
fetches the list successfully, you'd see: From Fetch
log.
After clicking on the delete button, though, you'd see: From the action
log but no From Fetch
because the action takes precedence over the instance.
Checkout this running sample below (open your JS console to see the logs):