0.7.1 • Published 6 years ago
logics v0.7.1
Logics
What Is Logics?
Logics is a library for defining and organizing the state of an application and the logic to manage it in the form of composable logics. It is built has a thin layer on top of Redux, Redux-Saga and Reselect.
How Does It Work?
Working with Redux usually implies having to define action types, action creators, and reducers in different files. Other files defining sagas and selectors also probably have to be added. This tends to make the code verbous and can lead to a certain complexity. Instead Logics defines the logic of an app in self contained and composable "logics":
const counterLogic = {
state: {
count: 0,
step: 1,
},
actions: {
decrement: {
payload: (step) => step,
handler: (state, step) => ({...state, count: state.count - step})
},
increment: {
payload: (step) => step,
handler: (state, step) => ({...state, count: state.count + step})
},
},
selectors: {
count: "@state.count"
},
};
Getting Started
Installation
npm install logics
Defining Logics
// /logics/display.js
export default {
state { // define the default state
message: "",
status: "",
},
actions: {
set: { // define an action
payload: (message, status) => ({message, status}), // function to build the payload of this action (for action creator)
handler: (state, {message, status=""}) => ({...state, message, status}) // reducer to handle this action
},
clear: { // define an other action
payload: null, // null means that the action will have no payload,
handler: () => ({message: "", status: ""})
},
},
};
// /logics/counter.js
export default ({defaultStep=1}) => { // define a configurable logic: (options) => logic
state: {
count: 0,
step: defaultStep,
},
actions: {
decrement: {
payload: (step) => step,
handler: (state, step) => ({...state, count: state.count - step})
},
increment: {
payload: (step) => step,
handler: (state, step) => ({...state, count: state.count + step})
},
setStep: {
payload: (value) => value,
handler: (state, value) => ({...state, step: value})
},
},
selectors: {
count: "@state.count",
},
};
// /logics/main.js
import api from "../api"; // import an hypothetic API
import {call, put} from "logics/effects";
import displayLogic from "./display-logic";
import counterLogic from "./counter-logic";
export default = {
__display: displayLogic, // use displayLogic as sub-logic
__counter: { // use counterLogic as sub-logic
logic: counterLogic(5), // logic will is merged to be extended
actions: {
saveCount: {
payload: (state) => state.count,
take: "latest", // take parameter indicates that hadler defines a saga
handler: function* (actions, {payload}) {
try {
yield put(actions.display.set("saving count..."));
yield call(api.saveCount(payload));
yield put(actions.display.set("count saved", "success"));
} catch (e) {
yield put(actions.display.set("error saving count", "error"));
}
}
},
},
};
Using Logics With React
// /components/LogicProvider.js
import {createLogicProvider} from "logics/react";
export default createLogicProvider();
// /components/counter.jsx
import React from "react";
import {LogicProvider} from "./LogicProvider";
const Counter = ({count, step, actions}) => {
const increment = () => actions.increment(step);
const decrement = () => actions.decrement(step);
const updateStep = (e) => {
const value = parseInt(e.currentTarget.value, 10);
actions.setStep(value);
};
const saveCount = () => actions.saveCount(count)
return (
<div>
<button onClick={decrement}>-</button> | {count} | <button onClick={increment}>+</button><br/>
<br/>
<span>step: </span><input type="text" value={step} onChange={updateStep}/><br/>
<br/>
<button conClick={saveCount}>Save</button>
</div>
);
};
export default LogicProvider.connect("counter")(Counter);
// /components/display.jsx
import React from "react";
import {LogicProvider} from "./LogicProvider";
export Display = (props) => {
const {message, status} = props["@state"];
return (
<div class={status}>{message}</div>
);
};
export defaut LogicProvider.connect("display")(Display);
// /app.jsx
import React from "react";
import ReactDOM from "react-dom";
import {LogicProvider} from "./LogicProvider";
import Counter from "./components/counter";
import Display from "./components/display";
import mainLogic from "./logics/main";
const App = () => {
const {getContext} = LogicProvider;
return (
<LogicProvider logic={mainLogic} name="app">
<Display />
<br/>
<Counter />
</LogicProvider>
);
};
ReactDOM.render(React.createElement(App), document.getElementById("app"));
Licence
The MIT License
Copyright (c) 2018 ANAE INTERACTIVE