-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Resource Components for Create, Update, Delete #32
Comments
🚨Name components with Resource prefixing action! 🚨 Rather than Here are updated examples: // --
// -- ResourceCreate
// --
<ResourceCreate resource="user" entityType="user">
{({create, onEventCreate, status}) => /* ... */}
</ResourceCreate>
// --
// -- ResourceUpdate
// --
<ResourceUpdate resource="user" entityType="user" needle={123}>
{({update, onEventUpdate, status}) => /* ... */}
</ResourceUpdate>
// --
// -- ResourceDelete
// --
<ResourceDelete resource="user" entityType="user" needle={123}>
{({delete, onEventDelete, status}) => /* ... */}
</ResourceDelete> |
Have mostly implemented this but I'd like to get a feature complete for all request methods and options like params/data, headers, etc. Currently we have |
I came across react-request and really appreciate a lot about it. The de-duping and caching functionality are exactly what I was hoping to solve through my own investigations for ResourceLoader in the future. In general I think moving the ResourceLoader to be a more standard API & HTTP request interface is a good thing and this library is a great reference. Besides the functionality I was really struck by the API design (both prop API and the render child result object API). Specifically for this issue the the A contrived example using a non-existing <Resource
// (url) Notice how you don't have to pass as resourceId
url="/book/15"
// (method) Defaults to get - Can be: GET, HEAD, OPTIONS, POST, PUT, PATCH, DELETE
method="get"
// (entityType) Optional triggers normilization
entityType="book"
// (lazy) Doesn't load on mount
lazy
>
{({ data: book, loading, error, response, status, doRequest }) => {
<div>
{loading && 'Loading...'}
{error && 'There was an error.'}
{!fetching &&
!error &&
response.status === 200 && (
<div>
<button onClick={() => doRequest()}>Load Book</button>;
<button onClick={() => doRequest({ method: 'delete' })}>Delete Book</button>;
<button
onClick={() =>
doRequest({ method: 'put', data: { title: 'Updated Title' } })
}
>
Update Book
</button>;
<button onClick={() => doRequest({ method: 'post', data: 'title' })}>
Delete Book
</button>;
<div>
<h1>Book: {book.title}</h1>
</div>
</div>
)}
</div>;
}}
</Resource> The API section is here: https://github.com/jamesplease/react-request#api For reference below is the API section copied from react-request README: Click to expandBelow from react-request READMEAPI
|
Method | Default value |
---|---|
GET, HEAD, OPTIONS | false |
POST, PUT, PATCH, DELETE | true |
<Fetch url="/books" lazy>
{({ doFetch }) => {
<button onClick={() => doFetch()}>Load the books</button>;
}}
</Fetch>
beforeFetch
A function that is called just before a network request is initiated. It is called
with one argument, an object with the following keys:
url
: The URL of the requestinit
: The second argument passed toglobal.fetch()
, which specifies things
such as the body, method, and so onrequestKey
: Either the computed request key, or the value of the
requestKey
prop
This feature is useful for analytics, or syncing response data with a data store such
as Redux.
Note: This function is not called when the component reads from the cache.
afterFetch
A function that is called anytime that a network response is received. It is called
with one argument, an object with the following keys:
url
: The URL of the requestinit
: The second argument passed toglobal.fetch()
, which specifies things
such as the body, method, and so onrequestKey
: Either the computed request key, or the value of the
requestKey
propresponse
: The response that was received from the HTTP requestdata
: The transformed data from the response. This will be different from
response.data
if atransformData
function was passed as a prop to<Fetch/>
.error
: An error returned from the HTTP requestdidUnmount
: A Boolean representing whether or not the component has unmounted
This can be used for analytics or syncing response data with a data store such
as Redux.
Note: This function is not called when the component reads from the cache.
onResponse
A function that is called every time a response is received, whether that
response is from the cache or from a network request. Receives two arguments:
error
and response
.
<Fetch
url="/posts/2"
onResponse={(error, response) => {
if (error) {
console.log('Ruh roh', error);
} else {
console.log('Got a response!', response);
}
}}>
{() => {
<div>Hello</div>;
}}
</Fetch>
transformData
A function that is called with the data returned from the response. You can use this
hook to transform the data before it is passed into children
.
<Fetch
url="/posts/2"
transformData={data => data.post>
{({ fetching, error, response, data }) => {
<div>
{fetching && ('Loading...')}
{error && ('There was an error.')}
{!fetching && !error && response.status === 200 && (
<div>
<h1>{data.title}</h1>
<div>{data.content}</div>
</div>
)}
</div>
}}
</Fetch>
Note:
transformData
does not modify the value ofresponse.data
. The transformed data is
made available to you in the render prop argument under thedata
key.
responseType
The content type of the response body. Defaults to "json"
unless the response has a 204 status code,
in which case it will be "text"
instead. Valid values are any of the methods on
Body.
Alternatively, you may specify a function that returns a string. The function will be called with one
argument: response
. This allows you to dynamically specify the response type based on information
about the response, such as its status code.
// If you have an endpoint that just returns raw text, you could, for instance, convert it into
// an object using `responseType` and `transformData`.
<Fetch
url="/countries/2"
responseType="text"
transformData={countryName => {
return {
countryName
};
}}>
{({ data }) => {
if (data) {
return <div>{data.countryName}</div>;
}
return null;
}}
</Fetch>
If the response body cannot be parsed as the responseType
that you specify, then data
will
be set to null
.
requestName
A name to give this request, which can help with debugging purposes. The request name is
analogous to a function name in JavaScript. Although we could use anonymous functions
everywhere, we tend to give them names to help humans read and debug the code.
<Fetch url={`/posts/${postId}`} requestName="readPost" />
Note: This feature is analogous to the operation name in GraphQL.
fetchPolicy
This determines how the request interacts with the cache. Valid options are:
"cache-first"
"cache-and-network"
"network-only"
"cache-only"
For documentation on what each of these values do, refer to the response caching guide.
The default value of this prop is based on the value of the method
prop that you pass to <Fetch/>
.
Method | Default value |
---|---|
GET, HEAD, OPTIONS | "cache-first" |
POST, PUT, PATCH, DELETE | "network-only" |
This prop behaves identically to the Apollo prop
with the same name.
cacheResponse
Whether or not the response will be cached. The default value is based on the value of the method
prop that you pass
to <Fetch/>
.
Method | Default value |
---|---|
GET, HEAD, OPTIONS | true |
POST, PUT, PATCH, DELETE | false |
For documentation on this prop, refer to the response caching guide.
dedupe
A Boolean value representing whether or not the request should be
deduplicated.
Defaults to true
.
requestKey
A string that is used to control the request deduplication and response caching features. By default,
a key is generated for you. Specifying a custom key is an advanced feature that you may not need.
For more, see the request key
guide.
The rest of the API documentation describes the other named exports from the react-request
package.
fetchDedupe( input [, init] [, dedupeOptions] )
This is the fetchDedupe
export from the Fetch Dedupe
library. Fetch Dedupe powers the request deduplication in React Request.
If, for whatever reason, you need to make a standalone HTTP request outside of the
<Fetch />
component, then you can use this with confidence that you won't send a
duplicate request.
For more, refer to the documentation of fetch-dedupe.
getRequestKey({ url, method, body, responseType })
Generates a request key. All of the values are optional.
This method comes from fetch-dedupe
.
isRequestInFlight( requestKey )
Return a Boolean representing if a request for requestKey
is in flight or not.
This method comes from fetch-dedupe
.
clearRequestCache()
Wipes the cache of deduped requests. Mostly useful for testing.
This method comes from fetch-dedupe
.
Note: this method is not safe to use in application code.
clearResponseCache()
Wipes the cache of cached responses. Mostly useful for testing.
Note: this method is not safe to use in application code.
Acknowledgements
This library was inspired by Apollo. The
library Holen was referenced during the
creation of this library.
react-request - Declarative HTTP requests for React
After some reflection providing a const doGet = options => doFetch({...options, method: 'get'});
const doHead = options => doFetch({...options, method: 'head'});
const doOptions = options => doFetch({...options, method: 'options'});
const doPost = options => doFetch({...options, method: 'post'});
const doPut = options => doFetch({...options, method: 'put'});
const doPatch = options => doFetch({...options, method: 'patch'});
const doDelete = options => doFetch({...options, method: 'delete'}); This would result in an updated contrived example: <Resource
// (url) Notice how you don't have to pass as resourceId
url="/book/15"
// (urlPost) URL used for POST requests; defaults to `url` prop value
urlPost="/book"
// (method) Defaults to get - Can be: GET, HEAD, OPTIONS, POST, PUT, PATCH, DELETE
method="get"
// (entityType) Optional triggers normilization
entityType="book"
// (lazy) Doesn't load on mount
lazy
>
{({ data: book, loading, error, response, status, doGet, doPost, doPut, doDelete }) => {
<div>
{loading && 'Loading...'}
{error && 'There was an error.'}
{!fetching &&
!error &&
response.status === 200 && (
<div>
<button onClick={() => doGet()}>Load Book</button>;
<button onClick={() => doDelete()}>Delete Book</button>;
<button
onClick={() =>
doRequest({ method: 'put', data: { title: 'Updated Title' } })
}
>
Update Book
</button>;
<button onClick={() => doRequest({ method: 'post', data: 'title' })}>
Delete Book
</button>;
<div>
<h1>Book: {book.title}</h1>
</div>
</div>
)}
</div>;
}}
</Resource> Note about
|
Rumor has it React Hooks will arrive this coming Monday Feb 4th. A custom const { data, loading, error, response, status, doGet, doPost, doPut } = useResource({
// (url) Notice how you don't have to pass as resourceId
url: "/book/15",
// (urlPost) URL used for POST requests; defaults to `url` prop value
urlPost: "/book",
// (method) Defaults to get - Can be: GET, HEAD, OPTIONS, POST, PUT, PATCH, DELETE
method: "get",
// (entityType) Optional triggers normilization
entityType: "book",
// (lazy) Doesn't load on mount
lazy
})
console.log({book: data.book}) // => will hold the book entity that was loaded |
Overview
We've found it quite convenient to use
ResourceLoader
components to setup data loading in our containers. It has become clear that providing the other CRUD operations as child render components would be useful. So I'd like to add the following components:New Components
NOTE: The following examples are not actually thought through so the items passed to the child render prop will likely be much different.
Other Possible Solutions
One thing that we could possibly do to provide this functionality is to provide functions for triggering Create, Update, Delete requests of the resource loaded by the
ResourceLoader
component. I highly doubt that is a good solution and even if it was it could make sense to build it from these new CrUD components.The text was updated successfully, but these errors were encountered: