Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dispatch is not a function useContext/useReducer React hooks

My Home.js component just doesn't seem to see the dispatch function at all. Do you guys know why? I'm kinda new to redux style state management stuff in redux.

I keep getting the error "TypeError: dispatch is not a function"

App.js

import React from 'react';
import { HashRouter, Route } from 'react-router-dom';

import Home from './pages/Home';
import Start from './pages/Start';
import Result from './pages/Result';

import RPSContextProvider from './contexts/RPSContext';

const App = () => {
    return (
        <HashRouter>
            <RPSContextProvider>
                <Route exact path="/" component={Home} />
                <Route path="/start" component={Start} />
                <Route path="/result" component={Result} />
            </RPSContextProvider>
        </HashRouter>
    );
};

export default App;

Home.js

import React, { useRef, useContext } from 'react';
import { RPSContext } from '../contexts/RPSContext';
import './home.css';

const Home = (props) => {
    const { state, dispatch } = useContext(RPSContext);
    const playerNameEntry = useRef();

    const handleClick = () => {
        if (!isStringEmpty(playerNameEntry.current.value)) {
            dispatch({ type: 'SET_NAME', state: playerNameEntry.current.value });
            props.history.push({
                pathname: '/start'
            });
            console.log(dispatch);
        }
    };

    const isStringEmpty = (string) => string.trim().length === 0;

    return (
        <div className="app-container">
            <h1>
                You dare battle me at
                <br />
                Rock, Paper, Scissors?
                <br />
                You got no chance, kid!
            </h1>
            <p>What's your name, ya chancer?</p>
            <input type="text" onKeyPress={(e) => handleKeyPress(e)} ref={playerNameEntry} />
            <button onClick={handleClick}>Start</button>
        </div>
    );
};

export default Home;

RPSContext.js

import React, { createContext, useReducer } from 'react';
import { RPSReducer } from '../reducers/RPSReducer';

export const RPSContext = createContext();

const RPSContextProvider = (props) => {
    const [ state, dispatch ] = useReducer(RPSReducer, { playerName: '' });

    return <RPSContext.Provider value={{ state, dispatch }}>{props.children}</RPSContext.Provider>;
};

export default RPSContextProvider;

RPSReducer.js

export const RPSReducer = (state, action) => {
    switch (action.type) {
        case 'SET_NAME':
            return { playerName: action };
        default:
            throw new Error();
    }
};

Basically as a first step I just want to set the name of the entry. I know this is quite a lot of code just for what I'm doing, but just wanting to try out useReducer and useContext so that I can learn all this new stuff in React.

like image 386
pyan Avatar asked Sep 26 '19 22:09

pyan


People also ask

How do I use dispatch in useReducer?

const [state, dispatch] = useReducer(reducer, initialState); This hook function returns an array with 2 values. The first one is the state value, and the second value is the dispatch function which is further used to trigger an action with the help of array destructuring. Note: The “state” can be of any kind.

What is Dispatch in useReducer in react?

The dispatch is the second value returned from the useReducer Hook and can be used in our JSX to update the state: // creating our reducer function function reducer(state, action) { switch (action.

Is dispatch in useReducer async?

React useReducer doesn't support async actions natively. Unlike Redux, there's no middleware interface, but hooks are composable. This is a tiny library to extend useReducer's dispatch so that dispatching async actions invoke async functions.

What is difference between useContext and useReducer?

React Context is a powerful state management feature in React. Instead of passing the props down through each component, React Context allows you to broadcast props to the components below. The useReducer hook is used for complex state manipulations and state transitions. …


2 Answers

I solved the problem by adding

    switch (action.type) {
        case 'SET_NAME':
            return { ...state, playerName: action.payload }

in my reducer, and in Home.js changed the state key I had in there to payload. Not 100% sure if it having the same name was effecting anything, but its much less confusing naming it payload.

    const handleClick = () => {
        if (!isStringEmpty(playerNameEntry.current.value)) {
            dispatch({ type: 'SET_NAME', payload: playerNameEntry.current.value });
like image 93
pyan Avatar answered Nov 07 '22 05:11

pyan


Wrap the whole App with AppContext.Provider passing with state and dispatch, like below

<AppContext.Provider value={{ state, dispatch }}>
  <div className="App">
    <Compo />
  </div>
</AppContext.Provider>
like image 22
Max Avatar answered Nov 07 '22 04:11

Max