Skip to content

linq2js/react-enhancer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

react-enhancer

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 (
    <>
      <button onClick={handleCounter1}>Increase Counter 1</button>
      <h2>Counter Value 1: {value1}</h2>
      <button onClick={handleCounter2}>Increase Counter 2</button>
      <h2>Counter Value 2: {value2}</h2>
    </>
  );
});

render(<App />, document.getElementById("root"));
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 (
    <>
      <form onSubmit={handleSubmit}>
        <input ref={inputRef} />
      </form>
    </>
  );
});

render(<App />, 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.

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(<App />, document.getElementById("root"));

Using use() to invoke custom hook

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(<App />, document.getElementById("root"));
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 (
    <>
      <button onClick={handleCounter}>Increase Counter</button>
      <h2>Counter Value: {counter}</h2>
      <button onClick={handleRegenerated}>Regenerate random value</button>
      <h2>Random Value: {randomValue}</h2>
    </>
  );
});

render(<App />, document.getElementById("root"));

Using context() to create simple todo app

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 (
      <form onSubmit={handleSubmit}>
        <input ref={inputRef} />
      </form>
    );
  });
});

const TodoList = stateful((props, { context }) => {
  return context(({ todos, dispatch }) => {
    return (
      <ul>
        {todos.map(todo => (
          <li key={todo.id} style={{ opacity: todo.done ? 0.5 : 1 }}>
            <button onClick={() => dispatch("toggle", todo.id)}>toggle</button>
            <button onClick={() => dispatch("remove", todo.id)}>remove</button>
            {todo.text}
          </li>
        ))}
      </ul>
    );
  });
});

const App = stateful((props, { context, state }) => {
  const [todos, setTodos] = state(initialState);
  const dispatch = (type, payload) =>
    setTodos(reducer(todos, { type, payload }));
  return context(
    { todos, dispatch },
    <>
      <TodoForm />
      <TodoList />
    </>
  );
});

render(<App />, document.getElementById("root"));

Using reducer(reducer, initialState) to create todo app

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 (
      <form onSubmit={handleSubmit}>
        <input ref={inputRef} />
      </form>
    );
  });
});

const TodoList = stateful((props, { context }) => {
  return context(({ todos, dispatch }) => {
    return (
      <ul>
        {todos.map(todo => (
          <li key={todo.id} style={{ opacity: todo.done ? 0.5 : 1 }}>
            <button onClick={() => dispatch("toggle", todo.id)}>toggle</button>
            <button onClick={() => dispatch("remove", todo.id)}>remove</button>
            {todo.text}
          </li>
        ))}
      </ul>
    );
  });
});

const handleTodosChange = console.log;

const App = stateful((props, { context, state, reducer }) => {
  const [todos, dispatch] = reducer(
    appReducer,
    initialState,
    handleTodosChange
  );

  return context(
    { todos, dispatch },
    <>
      <TodoForm />
      <TodoList />
    </>
  );
});

render(<App />, document.getElementById("root"));

Using store({ initialState, middleware, reducer, onChange }) to create redux like store

const TodoList = stateful((props, { context }) =>
  // extract todos from store
  context(({ todos, dispatch }) => (
    <ul>
      {todos.map(todo => (
        <li key={todo.id} style={{ opacity: todo.done ? 0.5 : 1 }}>
          <button
            onClick={() => dispatch({ type: "toggle", payload: todo.id })}
          >
            toggle
          </button>
          <button
            onClick={() => dispatch({ type: "remove", payload: todo.id })}
          >
            remove
          </button>
          {todo.text}
        </li>
      ))}
    </ul>
  ))
);

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
    }),
    <>
      <TodoForm />
      <TodoList />
    </>
  );
});

About

Enhancing for React stateless/function component

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published