Enhancing for React stateless/function component
npm install react-enhancerjsx harmony
import React from "react";
import { render } from "react-dom";
import { stateful } from "react-enhancer";
const App = stateful((props, { state }) => {
const defaultValue1 = 1;
const defaultValue2 = 2;
const [value1, setValue1] = state(defaultValue1);
const [value2, setValue2] = state(defaultValue2);
function handleCounter1() {
setValue1(value1 + 1);
}
function handleCounter2() {
setValue2(value2 + 1);
}
return (
<>
Counter Value 1: {value1}
Counter Value 2: {value2}
>
);
});
render( , document.getElementById("root"));
`
Using ref(), refer https://reactjs.org/docs/hooks-reference.html#useref
`jsx harmony
import React from "react";
import { render } from "react-dom";
import { stateful } from "react-enhancer";
const App = stateful((props, { ref }) => {
const inputRef = ref();
function handleSubmit(e) {
e.preventDefault();
alert(inputRef.current.value);
}
return (
<>
>
);
});
render( , document.getElementById("root"));
`
Using effect(factory, inputs), refer https://reactjs.org/docs/hooks-reference.html#useeffect
The default behavior for effects is to fire the effect once after completed render. That way an effect is always recreated if one of its inputs changes.
`jsx harmony
import React from "react";
import { render } from "react-dom";
import { stateful } from "react-enhancer";
const App = stateful((props, { effect, state }) => {
const [userInfo, setUserInfo] = state("Loading...");
effect(() => {
setTimeout(
() =>
fetch("https://api.github.com/users/linq2js")
.then(res => res.text())
.then(res => setUserInfo(res)),
2000
);
});
return <>{userInfo}>;
});
render( , document.getElementById("root"));
`
Using use() to invoke custom hook
`jsx harmony
import React from "react";
import { render } from "react-dom";
import { stateful } from "react-enhancer";
const userInfoHook = ({ effect, state }, name) => {
const [userInfo, setUserInfo] = state("Loading...");
effect(() => {
setTimeout(
() =>
fetch("https://api.github.com/users/" + name)
.then(res => res.text())
.then(res => setUserInfo(res)),
2000
);
});
return userInfo;
};
const App = stateful((props, { use }) => {
const userInfo = use(userInfoHook, "linq2js");
return <>{userInfo}>;
});
render( , document.getElementById("root"));
`
Using memo(factory, inputs), refer https://reactjs.org/docs/hooks-reference.html#usememo
`jsx harmony
import React from "react";
import { render } from "react-dom";
import { stateful } from "react-enhancer";
const App = stateful((props, { memo, state }) => {
const [regenerated, setRegenerated] = state(false);
const randomValue = memo(() => Math.random(), [regenerated]);
const [counter, setCounter] = state(1);
function handleRegenerated() {
setRegenerated(!regenerated);
}
function handleCounter() {
setCounter(counter + 1);
}
return (
<>
Counter Value: {counter}
Random Value: {randomValue}
>
);
});
render( , document.getElementById("root"));
`
Using context() to create simple todo app
`jsx harmony
import React from "react";
import { render } from "react-dom";
import { stateful } from "react-enhancer";
const initialState = [{ id: 1, text: "item 1" }, { id: 2, text: "item 2" }];
const reducer = (state, action) => {
if (action.type === "add") {
return [...state, { id: new Date().getTime(), text: action.payload }];
}
if (action.type === "remove") {
return state.filter(todo => todo.id !== action.payload);
}
if (action.type === "toggle") {
return state.map(todo =>
todo.id === action.payload ? { ...todo, done: !todo.done } : todo
);
}
return state;
};
const TodoForm = stateful((props, { ref, context }) => {
const inputRef = ref();
return context(({ dispatch }) => {
function handleSubmit(e) {
e.preventDefault();
dispatch("add", inputRef.current.value);
inputRef.current.value = "";
}
return (
);
});
});
const TodoList = stateful((props, { context }) => {
return context(({ todos, dispatch }) => {
return (
{todos.map(todo => (
-
{todo.text}
))}
);
});
});
const App = stateful((props, { context, state }) => {
const [todos, setTodos] = state(initialState);
const dispatch = (type, payload) =>
setTodos(reducer(todos, { type, payload }));
return context(
{ todos, dispatch },
<>
>
);
});
render( , document.getElementById("root"));
`
Using reducer(reducer, initialState) to create todo app
`jsx harmony
import React from "react";
import { render } from "react-dom";
import { stateful } from "react-enhancer";
const initialState = [{ id: 1, text: "item 1" }, { id: 2, text: "item 2" }];
const appReducer = (state, type, payload) => {
if (type === "add") {
return [...state, { id: new Date().getTime(), text: payload }];
}
if (type === "remove") {
return state.filter(todo => todo.id !== payload);
}
if (type === "toggle") {
return state.map(todo =>
todo.id === payload ? { ...todo, done: !todo.done } : todo
);
}
return state;
};
const TodoForm = stateful((props, { ref, context }) => {
const inputRef = ref();
return context(({ dispatch }) => {
function handleSubmit(e) {
e.preventDefault();
dispatch("add", inputRef.current.value);
inputRef.current.value = "";
}
return (
);
});
});
const TodoList = stateful((props, { context }) => {
return context(({ todos, dispatch }) => {
return (
{todos.map(todo => (
-
{todo.text}
))}
);
});
});
const handleTodosChange = console.log;
const App = stateful((props, { context, state, reducer }) => {
const [todos, dispatch] = reducer(
appReducer,
initialState,
handleTodosChange
);
return context(
{ todos, dispatch },
<>
>
);
});
render( , document.getElementById("root"));
`
Using store({ initialState, middleware, reducer, onChange }) to create redux like store
`jsx harmony
const TodoList = stateful((props, { context }) =>
// extract todos from store
context(({ todos, dispatch }) => (
{todos.map(todo => (
-
onClick={() => dispatch({ type: "toggle", payload: todo.id })}
>
toggle
onClick={() => dispatch({ type: "remove", payload: todo.id })}
>
remove
{todo.text}
))}
))
);
const handleStateChanged = state => console.log("state changed", state);
const loggerMiddleware = createLogger();
const App = stateful((props, { context, state, store }) => {
return context(
// create store and passing down to descendant components
store({
initialState,
reducer: appReducer,
middleware: loggerMiddleware,
onChange: handleStateChanged
}),
<>
>
);
});
``