Data Flow
GState could apply the concept of unidirectional data flow like Flux or Redux
React Todo example write with GState
Commands
let nextTodoId = 0;
export const addTodo = (state, text) => {
const id = nextTodoId++;
state.set({
todos: {
[id]: {
id,
text,
completed: false
}
}
});
};
export const setVisibilityFilter = (state, filter) => {
state.set({
filter: filter
});
};
export const toggleTodo = (state, id) => {
const completed = state.get(["todos", id, "completed"]);
state.set({
todos: {
[id]: {
completed: !completed
}
}
});
};
Commands is same with Redux’s reducers. They could be pure functions, take state as parameter, and use state.get to read, state.set to mutate. It is important because you could reuse the command’s business logic for any state context/path. It is also easy for testing:
test("test addToDo command", () => {
const state = new GState();
state.set({ todos: {} });
addToDo(state, "a");
expect(state.get({ todos: { _: 1 }}))
.toMatchObject({ todos:[{text: "a", completed: false}]});
});
Queries
import React from "react";
import TodoList from "./TodoList";
import gstate from "./gstate";
import { toggleTodo } from "./actions";
const getVisibleTodos = (todos = [], filter = "SHOW_ALL") => {
switch (filter) {
case "SHOW_ALL":
return todos;
case "SHOW_COMPLETED":
return todos.filter(t => t.completed);
case "SHOW_ACTIVE":
return todos.filter(t => !t.completed);
}
};
const TodoListWithState = gstate(
{
todos: {
_: 1
},
filter: 1
},
(props, data) => {
return (
<TodoList
todos={getVisibleTodos(data.todos, data.filter)}
onTodoClick={id => toggleTodo(props.state, id)}
/>
);
}
);
module.exports = TodoListWithState;
Queries use gstate state declarative high order component(same with Appollo’s graphql or Relay createFragmentContainer) which use state.watch to query information and render stateless components.