The Legend of Zelda triforce

Frontend Techniques in the Realm of Hyrule with React

Triforce

Adventure Log

Triforce

Adventure Overview

Log Entries

0

Items

0

Enemies

0

Quests

0

Add Adventure Log

Log Entries

No log entries yet. Go on an adventure!

1. What is useReducer?

useReducer is a hook that is used for managing complex state logic within your React components

const logReducer = (state, action) => {
  // reducer logic
};

const AdventureLog = () => {
  const [state, dispatch] = useReducer(logReducer, initialState);

  // ...
};

Use Cases

Complex logic state with multiple variables, sub-values, or when the next state depends on the previous state.

Examples:

  • State transitions based on actions (like validation)

  • Multi-step work flows

  • Managing component states (like tabs or accordions)


2. Configuring the reducer

Accepts:

  • A reducer function that determines how the state gets updated
  • An initial value for the state
  • [Optional] An initializer function that will return the initial state value

Returns:

  • The state
  • A dispatch function to update the state
// AdventureLog.tsx
const AdventureLog = () => {
  const initialState = {
    logEntries: [],
    logEntryTypes: {
      item: 0,
      enemy: 0,
      quest: 0,
    },
    items: [],
    enemies: [],
    quests: [],
  };

  const [state, dispatch] = useReducer(logReducer, initialState);
};

3. The Reducer Function

The reducer function handles state transitions. It accepts the current state and action (type) and returns the new state.

// AdventureLog.tsx
const logReducer = (state, action) => {
  switch (action.type) {
    case "ADD_LOG":
      return {
        ...state,
        logEntryTypes: {
          ...state.logEntryTypes,
          ...action.payload.logEntryTypes,
        },
        logEntries: [...state.logEntries, action.payload],
      };
    case "ADD_ITEM":
      return {
        ...state,
        items: [...state.items, action.payload],
      };
    case "ADD_ENEMY":
      return {
        ...state,
        enemies: [...state.enemies, action.payload],
      };
    case "ADD_QUEST":
      return {
        ...state,
        quests: [...state.quests, action.payload],
      };
    default:
      throw new Error("Unknown action type");
  }
};

4. Setting Up the Log Adventure Log Submission Form

// AdventureLog.tsx
const AdventureLog = () => {
  // .. Reducer logic

  const handleSubmit = (event) => {
    // ... logic to get form data

    switch (logType) {
      case "item":
        addItem(logEntry);
        break;
      // ... additional cases for enemy and quest
    }
  };

  return (
    <form>
      <select name="logType">
        // select options for item, enemy, and quest
      </select>
      <input type="text" name="logEntry" />
      <button type="submit" onClick={handleSumbit}>
        Add Adventure Log
      </button>
    </form>
  );
};

5. Dispatching Actions

// AdventureLog.tsx
const AdventureLog = () => {
  // ...
  // Add a new item to the the `items` array in state
  const addItem = (item) => ({
    type: "ADD_ITEM",
    payload: item,
  });
  // Add new log entry and increment `logEntryTypes[item]` in state
  const addLog = (logEntry, logType) => ({
    type: "ADD_LOG",
    payload: {
      logEntry,
      logType,
      logEntryTypes: {
        [logType]: state.logEntryTypes[logType] + 1,
      },
    },
  });
  // Dispatch state updates
  const handleAddItem = (newItem) => {
    dispatch(addItem(newItem));
    dispatch(addLog(`Collected item: ${newItem}`, "item"));
  };
  // ...
};