# Rayers. React layers. [Description](http://doc.a-level.com.ua/react-layers) # React Layers **NIH-syndrom again** ## Goal Create layered **React** microframework with reasonable architecture and minimal boilerplate. ## Architecture Layers, one-by-one from deepest layer (global state management, server queries) to directly **View** (react) layer: ### Pub (and Sub) Minimalistic pub/sub with recursive support builded on top of [Javascript Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) ```javascript const pub = createPub() pub.subscribe((state, key, oldValue, newValue) => console.log(state, key, oldValue, newValue)) pub.a = 5 pub.arr = ['foo', 'bar'] pub.arr[1] = 'baz' ``` On any change of keys in objects `subscriber` called. You can listen to updates in any nested object. Listening on upper level hears also nested updates. This way you can achieve global state tree without boilerplate, but this way requires attention to what you do with state. #### React Listening Hook `usePub`, obviously. Causes react component update on changing of pub. To minimize overhead, `usePub` can be used for nested pubs, instead of root state. ```javascript const arrPub = usePub(pub.arr) ``` Hook returns pub, so `arrPub === pub.arr`, but component updating when pub changes. #### Network Requests/Promises **Pub** can be easily used for tracking promises. !!! (error) Be careful, **storing promises in global state causes memory leaks** !!! ##### How 0. creating nested **Pub** with structure like ```javascript { promiseName1: {status, payload, error} promiseName2: {status, payload, error} } ``` 2. Writing function, which have `promiseName` and exactly promise as argument and updates promise pub branch when promise updating its state (**PENDING => FULFILLED** or **PENDING => REJECTED**), storing `status`, `payload` and `error` in promise pub named branch 3. ~~rtk-query~~: 4. - composing functions: query function, which returns promise and "thunk", which passed promise life through pub. Something like `createAsyncThunk`, or `createQuery`, with next parameters: - `promiseName`. - `queryFunc` - function, which returns promises. or even **carrying**: 1. `createQueryPub` creates pub with promises, some basic options passed (like cache timeout and probably queryFunc) and returns `createQuery` or object with functions from step 3 if queryFunc passed on first step into createQueryPub 2. `createQuery(queryFunc)` returns function, which: 3. receives `promiseName`, returns object with functions: - `query`, which accepts arguments and passes it to `queryFunc` - `usePromiseNameQuery`/`usePromiseNameMutation` like in `rtk-query` - and so... (no ideas right now, but something about atomic actions/force query/invalidate cache) ### Actions/Controllers/Thunks To avoid random messy access to global state, some functions which works with are welcome, but they aren't necessary. ### Routing Instead of moving Routing on React level, making routing ~~great again~~ separated from React Markup. #### Why - _Because_ - Routing describes _page_ content overall, but not how it will exactly looks (React does) - Routing describes **request** to backend, regardless of look. #### Two layers of routing: - address routing - hash routing #### Conclusion Routing configuration should be separated from React markup, and store next information: - **Route Template** like `/page/:id` - **Route Name** which probably same as one of promise names - **Query Func** or even **Query Params** to make query with **Pub**. **Query Func** can be made very easy with **GraphQL**. **Query Func** gets all information about route (or, at least, params from route) as function parameters to make query. Usually **Query Func** is just thunk with promise for Pub. - **React Page Component**, which should be rendered for this **Route**. Probably with **MetaPlate** to avoid _props drilling, `useHuy`, `map`, props waterfall, `usePizda`, `map`_ and so - **Some private routing configuration**, like `fallback` (address to go, if private route not accessible) and `roles` - list of user roles, which can visit this private page. Some HOC needed to provide current user roles list (usually from global state/jwt) to be matched with `roles` props #### some ideas and thoughts - address routing (from domain till ? - hash routing (from # till end of address) possible routing configuration: - list style, as JSON or JSX (like ) - tree style, potentially faster (but it doesn't matters on client side) ```javascript const treeRouteConfig = { //root page: "/": PageMain, //login '/login': PageLogin, //admin part with subroutes '/admin': { "/": PageAdminMain, // /admin/ "/users": PageAdminUsers, // /admin/users } } ``` A lot of questions at the moment about three configs: what if route params AND nested routes ?-params and hash layer - where is should be configured? looks like this configuration should be moved into page component, not to be in tree. so cancel tree idea for now ### View Layer (react) _Mostly_ template react components without boilerplate, hookafucking, billions of `useEffect` and so. **Styling** moved to **CSS** or... not. ## Tools - `createPub` and `qjp` (should be refucktored) from `v01` - Some wrapper around `react-router-dom` to pass query func to `Route` component or other configuration - **Metaplate**, which provides meta templating abilities to write nesting components page layout, according to nested query data without boilerplate and map - Something for **SSR** ## Additionals Some addons ### SSR For now no implementations about **SSR**, but there are some _ideas_: - CSSR. **Client Server Side Rendering** lol. Draw HTML in user browser, then upload it back to backend. Pros and cons: - Pros: - no need of backend SSR code - no load on server - Cons: - client-side load - client can scam - no SEO HTML before user comes to page - **Simplicity**. No backend code with all this **SSR** boilerplate. Using maximal isomorphy as it possible. - **Components** may have **stub** version. - **DOM-Elements** and/or **Components** may be marked as **private** for sensual information. This **DOM-Elements** or **Components** should not be rendered on backend (only stub rendered) - Marking components/elements as **private** gives ability to get seamless **SSR** without ~~almost~~ coding on backend. ## TODO - **Check speed** or **MetaPlate** on huge updates. - **Wrapper** around **react-router-dom**. - **SSR** library