Heis
Heis

Reputation: 568

Redux in a non react function

Im trying to get compare a state from the node express server with the state in the redux store. If the state is different i want to update the store state to the same value as the server state. Now im getting the problem that I can not use these hooks in a non react function. I need this to work but ive looked up the redux documentation and as far as i understand these hooks can only be used in a react function component. Is there another way to still make this work since my whole application is based on the redux state already.

import React from 'react';
import {useDispatch, useSelector} from 'react-redux';

 /**
 * get the gamestate from the server
 * @returns {Promise<{data: any}>}
 */
async function getGamestate() {
    const gameStates = await fetch('http://localhost:3000/game-state').then(response => response.json());
    return {
        data: gameStates,
    }
}


export async function CheckIfChanged(){
    const serverGameState = await getGamestate();
    const clientGameState = useSelector(state => state.gameState);

    if(serverGameState.data !== clientGameState){
        console.log(serverGameState)
        //UpdateGameState(serverGameState)

    }else {
        console.log("still the same")
    }
}

Update: Im planning to call the function here in the mainview, this is basically a wrapper thats used in the whole application. The checkIfChanged function will be called every 5 seconds or so.

import React from 'react';
import '../../style/App.scss';
import Wrapper from '../wrapper/wrapper';
import StartView from '../startview/StartView';
import { useSelector } from 'react-redux';

function MainView(){

  const gameState = useSelector(state => state.gameState);

  //arround here i would call it and will be updating every 5 seconds later
  checkIfChanged();

  switch (gameState) {
    case "notStarted":
      return (
        <StartView/>
      );
    case "video":
    case "keypad":
    case "puzzle":
    case "completed":
    case "failed":
      return (
        <Wrapper/>
      );
    default:
    return (
      <div className="contentArea">
        <h1>Er is een fout opgetreden</h1>
      </div>
    );
  }

}
export default MainView;

Upvotes: 3

Views: 1467

Answers (2)

Shubham Khatri
Shubham Khatri

Reputation: 281626

You can't define an async method with hooks directly in render. However you can convert your function in a custom hook which can then use useSelector and implement useEffect to sync your changes

import React from 'react';
import {useDispatch, useSelector} from 'react-redux';

 /**
 * get the gamestate from the server
 * @returns {Promise<{data: any}>}
 */
async function getGamestate() {
    const gameStates = await fetch('http://localhost:3000/game-state').then(response => response.json());
    return {
        data: gameStates,
    }
}


export function useCheckIfChanged(){ // not an async function
    const clientGameState = useSelector(state => state.gameState);
    const clientGameStateRef = useRef(clientGameState); 
    // Using a ref since we can't add clientGameState as a dependency to useEffect and it is bounded by closure

    useEffect(() =-> {
        clientGameStateRef.current = clientGameState;
    }, [clientGameState]);

    useEffect(() => {
          setInterval(async() => {
             const serverGameState = await getGamestate();
             // value inside here for clientGameState will refer to the original state only and hence we are using a ref which we update in another useEffect
             if(serverGameState.data !== clientGameStateRef.current){
                  console.log(serverGameState)
                 //UpdateGameState(serverGameState)

             }else {
                 console.log("still the same")
             }
          }, 5000)
    }, []);

}

import React from 'react';
import '../../style/App.scss';
import Wrapper from '../wrapper/wrapper';
import StartView from '../startview/StartView';
import { useSelector } from 'react-redux';

function MainView(){

  const gameState = useSelector(state => state.gameState);
  useCheckIfChanged(); // using the custom hook here

  switch (gameState) {
    case "notStarted":
      return (
        <StartView/>
      );
    case "video":
    case "keypad":
    case "puzzle":
    case "completed":
    case "failed":
      return (
        <Wrapper/>
      );
    default:
    return (
      <div className="contentArea">
        <h1>Er is een fout opgetreden</h1>
      </div>
    );
  }

}
export default MainView;

Upvotes: 3

Jacek Walasik
Jacek Walasik

Reputation: 517

You can update state by calling dispatch directly on store:

store.dispatch(actionName(values))

Redux documentation on handling store

Upvotes: 0

Related Questions