DEV Community

Discussion on: Post an Elegant Code Snippet You Love.

Collapse
 
thesmarthyena profile image
Philippe Skopal

Or this implementation of the Observer Design pattern in react.

import React, { useEffect, useReducer, createContext, useContext } from "react";
import "./styles.css";

const initialState = { trigger: 0, text: "", timestampedText: "" };

function reducer(state, action) {
  switch (action.type) {
    case "trigger":
      return { ...state, trigger: state.trigger + 1 };
    case "updateText":
      return { ...state, text: action.newValue, trigger: state.trigger + 1 };
    case "updateTimestampedText":
      return { ...state, timestampedText: action.newValue };
    default:
      return state;
  }
}

const StateContext = createContext(null);

const useStore = () => {
  return useContext(StateContext);
};

const TriggerListenerComponent = () => {
  const [state, dispatch] = useStore();

  useEffect(() => {
    dispatch({
      type: "updateTimestampedText",
      newValue: `${Date.now()} - ${state.text}`
    });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [state.trigger]);

  return <></>;
};

const Body = () => {
  const [state, dispatch] = useStore();

  const handleChange = (event) => {
    dispatch({ type: "updateText", newValue: event.target.value });
  };

  const handleClick = () => {
    dispatch({ type: "trigger" });
  };

  return (
    <>
      <div className="App">
        <p>
          Change the input to observe how the trigger works and can be used.
        </p>

        <p>
          Click to refresh manually the timestamped value (without changing the
          text).
        </p>
        <button onClick={handleClick}>Trigger</button>
        <br />
        <br />
        <input value={state.text} onChange={handleChange} />
        <br />
        <p> Unique timestamped text: {state.timestampedText} </p>
      </div>
      <TriggerListenerComponent />
    </>
  );
};

export default function App() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <StateContext.Provider value={[state, dispatch]}>
      <Body />
    </StateContext.Provider>
  );
}
Enter fullscreen mode Exit fullscreen mode