React Store not updating context with React.useReducer

I put together a working example, stubbing out your socket calls with a simple setTimeout.

Probably the most interesting part is where I moved the sendChatAction function into the component so it could use the dispatch method of the reducer:

export default function Store(props) {
  const [allChats, dispatch] = React.useReducer(reducer, initState);

  function sendChatAction(value) {
    dispatch({
      type: "RECEIVE_MESSAGE",
      payload: value
    });
  }

  ...
}

Everything appears to work. Compare your code to this:

Store.jsx

import React, { useEffect } from "react";

export const CTX = React.createContext();

const initState = {
  general: [
    { from: "matt", msg: "yo" },
    { from: "jeff", msg: "yo" },
    { from: "steve", msg: "yo" }
  ],
  topic2: [
    { from: "bill", msg: "yo" },
    { from: "joe", msg: "yo" },
    { from: "dave", msg: "yo" }
  ]
};

function reducer(state, action) {
  //payload logs as:
  //{from:'from',msg:'msg',topic:'topic'}
  const { from, msg, topic } = action.payload;
  switch (action.type) {
    case "RECEIVE_MESSAGE":
      return {
        ...state,
        [topic]: [...state[topic], { from, msg }]
      };
    default:
      return state;
  }
}

export default function Store(props) {
  const [allChats, dispatch] = React.useReducer(reducer, initState);

  function sendChatAction(value) {
    dispatch({
      type: "RECEIVE_MESSAGE",
      payload: value
    });
  }

  useEffect(() => {
    //msg logs with text field value that we need in
    //chatWindow on Dashboard.
    setTimeout(() => {
      sendChatAction({ from: "matt", msg: "hey", topic: "general" });
    }, 3000);
  }, []);

  //allChats logs only as initState, above.
  const user = "matt" + Math.random(100).toFixed(2);

  return (
    <CTX.Provider value={{ allChats, sendChatAction, user }}>
      {props.children}
    </CTX.Provider>
  );
}

Dashboard.jsx

import {
  Button,
  Chip,
  List,
  ListItem,
  ListItemText,
  Paper,
  TextField,
  Typography
} from "@material-ui/core";
import React from "react";
import { CTX } from "./Store";

export default function Dashboard() {
  const classes = {};
  //CTX store
  const { allChats, sendChatAction, user } = React.useContext(CTX);
  const topics = Object.keys(allChats);
  //local state
  const [activeTopic, changeActiveTopic] = React.useState(topics[0]);
  const [textValue, changeTextValue] = React.useState("");

  return (
    <div className={classes.root}>
      <Paper className={classes.root}>
        <Typography variant="h4" component="h4">
          Chat Room
        </Typography>
        <Typography variant="h5" component="h5">
          {activeTopic}
        </Typography>
        <div className={classes.flex}>
          <div className={classes.topicsWindow}>
            <List>
              {topics.map((topic) => (
                <ListItem
                  onClick={(e) => changeActiveTopic(e.target.innerText)}
                  key={topic}
                  button
                >
                  <ListItemText primary={topic} />
                </ListItem>
              ))}
            </List>
          </div>
          <div className={classes.chatWindow}>
            {allChats[activeTopic].map((chat, i) => (
              <div className={classes.flex} key={i}>
                <Chip label={chat.from} className={classes.chip} />
                <Typography variant="body1" gutterBottom>
                  {chat.msg}
                </Typography>
              </div>
            ))}
          </div>
        </div>
        <div className={classes.flex}>
          <TextField
            label="Send a Chat"
            className={classes.chatBox}
            value={textValue}
            onChange={(e) => changeTextValue(e.target.value)}
          />

          <Button
            variant="contained"
            color="primary"
            className={classes.button}
            onClick={() => {
              sendChatAction({
                from: user,
                msg: textValue,
                topic: activeTopic
              });
              changeTextValue("");
            }}
          >
            Send
          </Button>
        </div>
      </Paper>
    </div>
  );
}

App.js

import React from "react";
import Dashboard from "./Dashboard";
import Store from "./Store";
import "./styles.css";

export default function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <Store>
        <Dashboard />
      </Store>
    </div>
  );
}

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top