- React - A JavaScript library for building user interfaces
- Redux - RESTful HTTP client for JavaScript
- Rest - Predictable state container for JavaScript apps
React containers should be self aware and be able to fetch required data to pass it to components. Using HAL may cause to send multiple request to obtain this same data. This document shows possible solutions how this can be solved.
Lets assume that real API looks similar to:
- [root] - Contains only links to other endpoints
- [users] {userId} - Store information about user, Has link to user address
- [users] {userId} [address] - Returns information about user address
Graphical representaion
(root)
├──get-user(userId)
│ └──get-address
└─ ...
If react consist component as described bellow:
- UserView
- UserContainer
- UserDetailsComponent
- UserAddressComponent
UserContainer could fetch all data and pass it to components. It has drawback because if a new data should be present on view (for example: Group names where user belong) it will require change of login in UserContainer.
The basic solution is to move logic, so that each component-container pair will be self aware to fetch data and present it. The only required parameter will be resoure from whcih the data can be obtained.
If react consist component as described bellow:
- UserView
- UserContainer
- UserDetailsContainer
- UserDetailsComponent
- UserAddressContainer
- UserAddressComponent
UserDetailsContainer and UserAddressContainer depends on resource property, which is a resource from restjs which allow to fetch desired data.
Each components should have this same hierartical order as presenter in HAL API.
(UserView)
├──UserContainer
│ ├──UserDetailsContainer
│ │ ├ UserAddressContainer
│ │ └─UserAddressComponent
│ └──UserDetailsComponent
...
UserContainer :
- Should fetch root api and pass Resource allowing to fetch UserDetails to UserDetailsContainer
UserDetailsContainer :
- Should fetch user details using resource
- Should pass fetched data to UserDetailsComponent
- Should pass UserAddress resource to UserAddressContainer
UserAddressContainer :
- Should fetch user details using resource
- Should pass fetched data to UserAddressComponent
<UserContainer resource={rootResource}>
<UserDetailsContainer resource={userDetailsResource}>
<UserDetailsComponent data={userDetails} />
<UserAddressContainer resource={userAddressResource} >
<UserAddressComponent data={userAddress} />
<UserAddressContainer />
</UserDetailsContainer>
</UserContainer>
Each component have to:
- Fetch Data using resource passed by parent and pass it to container
Ech component may to:
- Pass to childeren resource allowing to fetch data required by children
- Resource is stored in store so there is no necessary to start building resource and set 'follow' from rootApi -> Amount of request is reducet
- When there is necessary to display a new data only the parent container has to change. (Its easy, because the structure is this same as in HAL)
The resource should be stored inside store, thanks to resourceReducer. Because of HTTP specification only GET requests may be cached. It solve a lot of problem, because to cache respirce information only resourceName and resourceParameters are required
{
"resource": {
"root": [{
"parentParams": null,
"resource": "ResourceObject",
"links": {
"userDetails": [{
"parentParams": null,
"resource": "ResourceObject",
"links": {
"userAddress": [{
"parentParams": {
"userId": 4
},
"resource": "ResourceObject"
}, {
"parentParams": {
"userId": 5
},
"resource": "ResourceObject"
}]
}
}]
}
}]
}
}
Thanks to this solution its very easy to fetch user details (just grab the userDetails resource and execute) and also to get userAddress. If passed userId does not exist, need to call parent resource, with given userId and fetch userAddress again.
To simplify usuage, spereate service should be created, which will accept follow path which is an array of objects.
getResource(["userDetails", {name:"userAddress", params:{ userId:4 }}])
Service should automatically traverse all stored resources by name, and check if parentParams match. If argument is a string where it should be automatically resolved to an object, where name key is set to stringValue, and params should be null
Thanks to nesting component we may be sure that required follow path has been already stored and it may be used without generating requests again.