Open allanchau opened 6 years ago
@allanchau, I think this is a great idea and I've been thinking about it a lot lately. I've come to the conclusion that it would be better to start turning Linz into multiple react apps (i.e one for the model index, one for the record edit, one for the overview page, etc).
This allows us to dip our toes in rather than biting off the whole damn thing allowing us to make some progress and release something better than what we have today, sooner than what we can if we migrate the whole app.
At present, I can't get my head around permissions, record/overview actions and a few other things and how they fit in to a react workflow without MASSIVE breaking changes required.
What are your thoughts on that?
I think permissions can be handled using the example above with middleware. As long as the react route is last, the api should kick in first?
We would just need to standardise the success
and error
responses coming from the routes.
I'm thinking 1 React App would be better though, it would allow us to take full advantage of code splitting out of the box assuming we go with create-react-app
. I think to make these changes incrementally, we just need to update (remove the rendering component) of routes as we go and let the React app handle getting the data? Anything else would just render using Jade as it currently does.
I might fork Linz and eventually create a feature branch here once I get most of the routes working.
I don't see how the permissions will work as they currently stand? The react app would just be one HTML request, all subsequent being XMLHTTPRequest/Fetch requests?
Could you explain a little more about how we could do it as one app but incrementally roll it out?
A more complete list of the things I'm unsure of are:
A couple of workflows that I can see as being tricky to do in React would be:
Could you detail how would they work a little more?
So using the example
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'build')));
// All existing routes go here
// Updated routes will need to have the render method and all middleware replaced with a res.json
// Handles any requests that don't match the ones above
app.get('*', (req,res) =>{
res.sendFile(path.join(__dirname+'/client/build/index.html'));
});
The fetch requests from the react app will now receive a structured response from the routes that it can use to display information to the user.
{
"data": {},
}
{
"error": {}
}
If there is a permission issue, the app will receive an error and display that to the user.
I'm not really sure how we can get around these either:
Flash functionality will probably be removed as it is now and replaced with a specific property in the son response, maybe
{
"data": {},
"flash": {
"message": "",
"options": { noty options },
}
}
{
"error": {},
"flash": {
"message": "",
"options": { noty options },
}
}
The modal record actions would work the same as the currently do (although I wouldn't mind getting rid of the query bind data plugin), the react app would still have access to query etc so click -> react app fetches HTML -> react app puts it in a modal (new component) -> trigger the modal
.
In terms of the page refreshing with new data, that can be handled by React animations, I haven't used it yet, but I assume it can be made to fade in and out like when an iOS Table View is updated.
Yeah, I thought more about it last night and I can see how the permissions will work, and how we can do it progressively too.
We'll have to do a little more homework on the widgets side of things. Some sort of means to package them up via the Express app (where all of the DSL is defined) and deliver to the client.
The page refreshing the data can't be handled by React animations alone? How would it would know when a particular modal needs data to be refreshed and another doesn't? I have seen some solutions in which a websocket connection receives data table updates from the server, but it seems quite complex when you think about filtering and paging too.
In terms of refreshing the data, I think we'll need to expose some sort of client-side Linz API so that we can offer modals and widgets a means to refresh the view when needed...
Wouldn't the child component (filter etc) just update the state on the parent? Once the state has changed, that would automatically cause a refresh.
In terms of when the data is updated directly and not through the UI it would be up to the user to refresh the page just like it is now.
I'd imagine the parent component would need to have a state with properties that match what we need to make the mongoose query or even store the query itself.
Yeah, the child component would update the state on the parent, and cause a refresh. The client-size Linz API was to solve the problem of a record action showing in a modal with the workflow:
Because it's POSTed, the data is automatically redrawn as it is today. So we'll need something to say, Okay Linz, I've done some stuff that altered the state, please reload from the server... type of thing.
I think anything we do should also involve GraphQL. I've been using it lately and it would be really useful for this project. Also, I think we should take a look at https://nextjs.org/ and see if it would be useful? I can see how using something like https://github.com/zeit/next.js/tree/master/examples/custom-server-express would make it much easier for us to wrap it custom cell renders, widgets, etc...
Just an idea, we should turn Linz into a react app.
Benefits
Notes
create-react-app
should be used.app.use(express.static(path.join(__dirname, 'build')));
app.get('/someroute', function(req, res) { res.json({ test: 'test' }); });
// Handles any requests that don't match the ones above app.get('*', (req,res) =>{ res.sendFile(path.join(__dirname+'/client/build/index.html')); });