farrow-next
farrow-next is an upper-level business framework based on the next.js package, containing
A conceptual architecture based on the classic
MVCA
redux-basedstate managementBased on the model of
Inverse of ControlandDependency Injectionto manage business codeProvides a friendly
React-Hooks apiWraps
cookie|fetch|userAgentand other convenient isomorphic methodsBased on
TypeScriptdevelopment, providing good type derivation capabilities...
Installation#
Contents#
Basic Usage#
Each page consists of 3 parts: Model, View, Controller.
Modelmanages the state of the application and its changesViewmanages the interface of the application and its event bindingControllermanages the asynchronous interaction of the application (e.g. requesting data)
In farrow-next, the Model is inside the Controller and each Controller has its own Model that it maintains.
Each Model consists of state and reducers/actions, which can be understood as a redux-store.
There is only one View, but there can be multiple Controllers.
The View accesses the state, actions and other properties or methods inside each Controller through the hooks api.
Step 1: Define the Controller#
Controller can be defined as many times as needed.
Step 2: Defining View#
A View is a React Component, and in any function component, you can:
Get an instance of
ControllerwithController.use().Pull state data from
ControllerviaController.useState(selector?), and automatically update the view when the state changes
Step 3: Create the Page component#
After completing the two steps, we need to bind them together to create a page.
Step 4: Expose the Page component#
In pages/xxx.ts, expose the Page component to be accessible via url.
API#
React Hooks API#
Controller.use()#
Get the Controller instance in the React Function Component
Controller.useState(selector?, compare?)#
Get and listen to Controller's state in React Function Component
- selector (optional) with
stateas argument returns the result of the state selected from it, default is state => state - compare (optional), with
(currState, prevState), returnstrueif the component needs to be re-rendered, orfalseif it is not. The default isshallowEqualwhich is shallow compared two object.
usePageInfo(): PageInfo#
usePageInfo to access current page info
useQueryChangedEffect(effectCallback)#
useQueryChangedEffect to perform effect when query was changed
Controller API#
controller.initialState#
Initial state of the Controller to initialize the redux store
controller.reducers#
The reducers object of a Controller contains the reducer function to update the state.
reducers is an object { [key: string]: Reducer } whose key is its action-type.
controller.store#
Access the redux-store constructed from initialState/reducers
controller.state#
Accesses the current this.store.getState() latest state
controller.actions#
Accesses the actions update function of redux-store, with the same structure as this.reducers.
controller.page#
Access the data associated with NextPageContext, structured roughly as follows
controller.devtools#
Whether to enable redux-devtools, default is true.
Supports boolean | string, if it is string, it will be displayed as the name in redux-devtools, which can be displayed normally even after compressing the code (the default name is the class name of Controller.name, which becomes a single letter after compressing.
controller.logger#
Whether to enable redux-logger, default is false.
controller.fetch(url:string, options?: RequestInit)#
fetch method wrapper, automatically handles cookie passing internally, interface is consistent with global variable fetch
See fetch documentation for more information.
controller.getJson(url:string, params?:object, options?: RequestInit): json#
The controller.getJson method is a method based on the controller.fetch wrapper to make it easier to send get requests.
The url parameters are handled in the same way as the controller.fetch method.
The params parameter will be internally querystring.stringify and spliced after the url.
The options parameter will be passed as options for the fetch.
controller.postJson(url:string, body?:object, options?:RequestInit): json#
The controller.postJson method is based on the controller.fetch wrapper method, and is a simpler way to send post requests.
The url parameter is handled in the same way as the controller.fetch method.
If the data is an object, it will be internally JSON.stringify and then sent to the server as a request payload
The options parameter will be passed as options for the fetch.
controller.getCookie(key:string)#
controller.getCookie is used to get the value of the cookie corresponding to the key parameter.
controller.setCookie(key:string, value:string, options?:object)#
controller.setCookie is used to set the value of the cookie corresponding to the key parameter. The third parameter options is an object, see documentation
controller.removeCookie(key:string, options?:object)#
controller.removeCookie is used to remove the value of the cookie corresponding to the key parameter. The third parameter options is an object, see documentation
controller.redirect(url)#
controller.redirect is used to redirect, it will take care the server/client, and chose the right way to redirect.
controller.isClient#
controller.isClient is a boolean value that determines whether the client is currently on the server.
controller.isServer#
controller.isServer is the boolean value that determines whether the client is currently on the server side.
controller.userAgent#
Gets the userAgent string, which can be used to construct other properties or methods such as controller.isWeixin.
controller.use(Controller)#
The controller.use method is used to implement dependency injection and returns the instance of the used class.
See Dependency Injection for more on this.
Controller Life-Cycle#
controller.preload?(): Promise<void>#
Call on preload phase(before component rendering), you can fetch SSR related data in this method
Page Api#
Dependency Injection#
The Controller class implements dependency injection, meaning that within a Controller, instances of other controllers can be injected via this.use(Controller), and can even refer to each other.
This mechanism facilitates modularity by giving preference to combinations over inheritance.