0.0.6 • Published 5 years ago

react-mx v0.0.6

Weekly downloads
2
License
ISC
Repository
github
Last release
5 years ago

react-mx

Counter App

import React from "react";
import { render } from "react-dom";
import mx from "react-mx";

const Count = {
  value: 1
};
// computed state
const DoubleCount = {
  state: Count,
  value: state => state * 2
};
const Increase = {
  state: Count,
  dispatch: (state, step = 1) => state + step
};
const App = () => {
  const [count, doubleCount, increase] = mx(Count, DoubleCount, Increase);

  return (
    <>
      <h1>Count: {count}</h1>
      <h1>Double Count: {doubleCount}</h1>
      <button onClick={() => increase()}>Increase</button>
      <button onClick={() => increase(2)}>Increase 2</button>
    </>
  );
};

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

Todo App

import React, { useRef } from "react";
import { render } from "react-dom";
import mx from "react-mx";

const Todos = {
  value: []
};
const AddTodo = {
  // using state helper to mutate state (prop name starts with $ sign)
  $state: Todos,
  dispatch($todos, text) {
    $todos.push({ id: Math.random().toString(36), text, done: false });
  }
};
const RemoveTodo = {
  $state: Todos,
  dispatch($todos, id) {
    $todos.filter(x => x.id !== id);
  }
};
const ToggleTodo = {
  $state: Todos,
  dispatch($todos, id) {
    $todos.map(todo => (todo.id === id ? { ...todo, done: !todo.done } : todo));
  }
};
const App = () => {
  const [todos, addTodo, removeTodo, toggleTodo] = mx(
    Todos,
    AddTodo,
    RemoveTodo,
    ToggleTodo
  );
  const inputRef = useRef();

  const handleSubmit = e => {
    e.preventDefault();
    addTodo(inputRef.current.value);
    inputRef.current.value = "";
  };

  return (
    <>
      <form onSubmit={handleSubmit}>
        <input ref={inputRef} />
      </form>
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>
            <button onClick={() => toggleTodo(todo.id)}>Toggle</button>
            <button onClick={() => removeTodo(todo.id)}>Remove</button> <span style={{ textDecoration: todo.done ? "line-through" : "none" }}>{todo.text}</span>
          </li>
        ))}
      </ul>
    </>
  );
};

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

Greeting App

import React from "react";
import { render } from "react-dom";
import mx from "react-mx";

const FirstName = {
  value: ""
};
const LastName = {
  value: ""
};
const FullName = {
  first: FirstName,
  last: LastName,
  value: ({ first, last }) => first + " " + last
};
const UpdateName = {
  first: FirstName,
  last: LastName,
  // can update multiple states at once
  dispatch(states, type, value) {
    if (type === "first") {
      return { first: value };
    }
    return { last: value };
    // return { first: FirstNameValue, last: LastNameValue } to update both states
  }
  /**
   * another dispatch version using state helper
   * $first: FirstName
   * $last: LastName
   * dispatch({ $first, $last }, type, value) {
   *   if (type === 'first') {
   *     $first.value = value;
   *   }
   *   else if (type === 'last') {
   *     $last.value = value;
   *   }
   * }
   */
};
const App = () => {
  const [first, last, full, update] = mx(
    FirstName,
    LastName,
    FullName,
    UpdateName
  );
  return (
    <>
      <input
        placeholder="First name"
        value={first}
        onChange={e => update("first", e.target.value)}
      />
      <input
        placeholder="Last name"
        value={last}
        onChange={e => update("last", e.target.value)}
      />
      <h1>{full}</h1>
    </>
  );
};

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

Using flow

import React, { useEffect } from "react";
import { render } from "react-dom";
import mx from "react-mx";

// define power states
const PowerOff = {
  value: "off",
  on: [["toggle", () => PowerOn]]
};
const PowerOn = {
  value: "on",
  on: [["toggle", () => PowerOff]]
};

// define traffic light states
const TrafficLightOff = {
  value: "off",
  on: [["on", () => GreenLightOn]]
};

const GreenLightOn = {
  value: "green",
  on: [["timer", () => YellowLightOn], ["off", () => TrafficLightOff]]
};

const YellowLightOn = {
  value: "yellow",
  on: [["timer", () => RedLightOn], ["off", () => TrafficLightOff]]
};

const RedLightOn = {
  value: "red",
  on: [["timer", () => GreenLightOn], ["off", () => TrafficLightOff]]
};

// create flows
const PowerFlow = mx.flow(PowerOff);
const TrafficLightFlow = mx
  .flow(TrafficLightOff)
  // should turn on/off when power state changed
  .listen(PowerFlow, value => [value]);

const App = () => {
  // using flow hooks
  const [power, sendPowerCommand] = PowerFlow.use();
  const [traffic, sendTrafficCommand] = TrafficLightFlow.use();

  useEffect(() => {
    const timerId = setInterval(() => {
      sendTrafficCommand("timer");
    }, 2000);
    return () => {
      clearInterval(timerId);
    };
  }, [sendTrafficCommand]);

  return (
    <>
      <div
        style={{
          width: 100,
          height: 100,
          borderRadius: 100,
          backgroundColor: traffic === "off" ? "gray" : traffic
        }}
      />
      <button
        style={{ backgroundColor: power === "on" ? "green" : "red" }}
        onClick={() => sendPowerCommand("toggle")}
      >
        {power === "on" ? "Turn power off" : "Turn power on"}
      </button>
    </>
  );
};

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