Frontend Framework for React and Formula.
npm install --save react formula xanderA minimal xander app with home and 404 page.
// Import the boot function to intialize xander.importReactfrom"react";import{render}from"xander";// Import style onto the page.require("./app.css");// Define routes for the app.letroutes=[{path: "/",component: props=><div>Hello, World.</div>},{path: "*",component: props=><div>404 NOT FOUND</div>}];// Render your app to the DOM.render({
routes
},document.getElementById("root"));Render xander with React's render function.
// Import the boot function to intialize xander.import{app}from"xander";importReactfrom"react";importReactDOMfrom"react-dom";importroutesfrom"./routes";letApp=app({ routes });// Define routes for your app.// Boot the app into a root DOM element. Map your URLs to component to render.ReactDOM.render(<App/>,document.getElementById("root"));A link component to hyperlink your app without annoying page refreshes.
import{Link}from'xander'<Linkto="/buckets">Go to my buckets</Link>The Eval component calculates the result of a formula expression.
import{Eval}from'xander'<Evalexp="SUM(A, B)"values={A: 2,B: 2}/>The Rule component renders HTML describing a formula expression.
import{Rule}from'xander'<Ruleexp="SUM(A, B)"/>The Loadable HOC works with webpack to split your app into chunks that load dynamically.
import{loadable}from"xander";letroutes=[{path: "/",component: loadable({loader: ()=>import("./home"),loading: (props)=><div>Loading...</div>delay: 500// 0.500 seconds})}];The Container component renders the router's current component.
import{Link}from"xander";render(<Container/>);The Connect HOC component syncs the store with React state.
import{connect,Container}from"xander";connect(Container);A minimal router, backed by the history API.
import{router}from"xander";router.open("/buckets/1");Use redirect to modify URL without adding an entry to the history state.
router.redirect("/buckets");Load routes and related configuration without app or render.
import{router}from"xander";router.loadRoutes([{path: "/",component: require("./pages/home")}]);The window store keeps track of window size and scroll location; syncs with DOM.
import{loadWindowStore}from"xander";loadWindowStore();Create custom stores to store your app's data.
import{createStore}from"xander";createStore(key,reducerOrSpec,actionsAndQueries);// example store, access via the key `todos` in react props.lettodosStore=createStore('todos',{getInitialState: ()=>[]addTodo: (state,todo)=>state.concat(todo),removeTodo: (state,id)=>state.filter(d=>d.id!==id)})// usagexandertodosStore.addTodo({id: 1,desc: "Make new framework"})todosStore.addTodo({id: 2,desc: "Write killer app"})todosStore.addTodo({id: 3,desc: "Analyze competition"})todosStore.removeTodo(3)todosStore.subscribe((state,action)=>console.log('todos changes',state,action))todosStore.dispatch('addTodo',{id: 4,desc: "Write product examples"})A store responds to actions by returning the next state.
constinc='inc'import{createStore}from'xander';// a simple counting storevarstore=createStore("count",(state=0,action)=>{switch(action.type)case inc:
returnstate+1;case incN:
returnstate+action.data;
default:
returnstate;},{inc: (state)=>dispatch('inc'),incN: (state,count)=>dispatch('incN',count),})// the store includes a reference to dispatchstore.dispatch('inc')// optionally, define action creators into the store.store.inc()Optionally, you may define a store with a specification.
constinc="inc";import{createStore}from"xander";// a simple counting storevarcountStore=createStore("count",{// life-cycle method for initialization.getInitialState: ()=>0,// handles { type: 'inc' }inc: state=>state+1,// handles { type: 'incN' }incN: (state,n)=>state+n});// object spec makes action creators automatically...countStore.inc();countStore.incN(10);Here is a list of store properties that are part of the public API.
| name | comment |
|---|---|
| name | The name of the store |
| dispatch | Access to dispatch function |
| dispatchToken | A number used to identity the store |
| subscribe | A function to tegister a listener |
| getState | A function to access state |
| setState | Replace the store's state |
| replaceReducer | Replace the store's reducer |
The entry point to effecting state changes in the app is when an action is dispatch.
Dispatch accepts action as object, promise, or type/data; returns promise.
// Import the dispatch function.var{ dispatch }=require('xander')// Dispatch action as objectdispatch({type: 'openPath','/user/new'}).then(action=>console.log('Going',action.data))// Dispatch action as promisedispatch(Promise.resolve({type: 'get',mode: 'off the juice'}))// Dispatch action with type:string and data:object.dispatch('loadSettings',{a: 1,b: 2})import{createStore}from"xander";// creates a key="A" in the root store, connected to a reducer function.letstoreA=createStore("a1",(state=0,action)=>(action.type==="setA" ? action.data : state));letstoreB=createStore("b1",(state=0,action)=>(action.type==="setB" ? action.data : state));// Store with dependencies on state in storeA and storeB.letstoreC=createStore("c1",(state=0,action,waitFor)=>{// Ensure storeA and storeB reducers run prior to continuing.waitFor([storeA.dispatchToken,storeB.dispatchToken]);// Side effect! Reads state from other stores after they are updated.returnstoreA.getState()+storeB.getState();});Returns an object with the store's state by key.
import{getState}from"xander";getState();Returns an object with the stores by key.
import{getStores}from"xander";getStores();Rehydrate the root state.
import{replaceState}from"xander";replaceState({MyCountStore: 1});Listen to changes to all stores. This will trigger once each time createStore or dispatch is invoked.
var unsubscribe = subscribe( (state, action) => {
// got change
})
// stop listening
unsubscribe()
Please note that action will be undefined when createStore is invoked.