Better useXxxApi (#34)
useXxxApi:
    use PollingReducer as a configuration provider
    provide pushAPIs, which update respective state with:
        pushing status
        push result
PollingReducer:
    rename to configurationReducer
    move polling indication to it's respective state
    XxxState.polling = 'true/false'
Reviewed-on: http://192.168.8.55:3000/HQLAx/CordaCheckers/pulls/34
			
			
This commit is contained in:
		
							parent
							
								
									82f5b07256
								
							
						
					
					
						commit
						2482226e0e
					
				@ -9,7 +9,9 @@ import About from "./components/About"
 | 
			
		||||
import Games from './container/Games';
 | 
			
		||||
import Leaderboard from './container/Leaderboard';
 | 
			
		||||
 | 
			
		||||
import usePollingReducer from './reducer/polling';
 | 
			
		||||
import useConfigReducer from './reducer/config';
 | 
			
		||||
import useUserReducer from './reducer/user';
 | 
			
		||||
import useLeaderboardReducer from './reducer/leaderboard';
 | 
			
		||||
import useGamesReducer from './reducer/games';
 | 
			
		||||
 | 
			
		||||
import useUserApi from './api/user';
 | 
			
		||||
@ -17,35 +19,40 @@ import useLeaderboardApi from './api/leaderboard';
 | 
			
		||||
import useGamesApi from './api/games';
 | 
			
		||||
 | 
			
		||||
export default function App() {
 | 
			
		||||
  const pollingReducer = usePollingReducer();
 | 
			
		||||
  const [config, dispatcConfig] = useConfigReducer();
 | 
			
		||||
 | 
			
		||||
  const leaderboard = useLeaderboardApi().poll(pollingReducer);
 | 
			
		||||
  const user = useUserApi().get();
 | 
			
		||||
 | 
			
		||||
  const [games, dispatchGames] = useGamesReducer();
 | 
			
		||||
  const gamesApi = useGamesApi(dispatchGames);
 | 
			
		||||
  gamesApi.list(pollingReducer);
 | 
			
		||||
  const user = useUserApi(useUserReducer()).getUser();
 | 
			
		||||
  const leaderboard = useLeaderboardApi(useLeaderboardReducer(), config).pollTable();
 | 
			
		||||
 | 
			
		||||
  const players = {
 | 
			
		||||
    leaderboard,
 | 
			
		||||
    isCurrentUser: (playerName) => user?.isCurrentUser(playerName) === true ? true : null
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const gamesReducer = useGamesReducer();
 | 
			
		||||
  const gamesApi = useGamesApi(gamesReducer, config);
 | 
			
		||||
  const games = gamesApi.pollGamesList();
 | 
			
		||||
 | 
			
		||||
  const isPolling = {
 | 
			
		||||
    games: games.isPollingGamesList,
 | 
			
		||||
    leaderboard: leaderboard.isPollingTable
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <BrowserRouter>
 | 
			
		||||
      <Header pollingReducer={pollingReducer} />
 | 
			
		||||
      <Header configReducer={[config, dispatcConfig]} isPolling={isPolling}/>
 | 
			
		||||
      <Routes>
 | 
			
		||||
        <Route path='/' element={<About />} />
 | 
			
		||||
        <Route path='/about' element={<About />} />
 | 
			
		||||
        <Route path='/games/*' element={<Games context={{ games, dispatchGames, gamesApi }} players={players} />} />
 | 
			
		||||
        <Route path='/games/*' element={<Games context={{ gamesReducer, gamesApi }} players={players} />} />
 | 
			
		||||
        <Route path='/leaderboard' element={<Leaderboard players={players} />} />
 | 
			
		||||
      </Routes>
 | 
			
		||||
    </BrowserRouter>
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function Header({ pollingReducer }) {
 | 
			
		||||
  const [polling, dispatchPolling] = pollingReducer;
 | 
			
		||||
function Header({ configReducer, isPolling }) {
 | 
			
		||||
  const [config, dispatcConfig] = configReducer;
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className='Header'>
 | 
			
		||||
@ -54,8 +61,8 @@ function Header({ pollingReducer }) {
 | 
			
		||||
      </h1>
 | 
			
		||||
 | 
			
		||||
      <OnlineToggle
 | 
			
		||||
        isOnline={polling.enabled}
 | 
			
		||||
        onClick={() => dispatchPolling({ type: 'toggleOnOff' })}
 | 
			
		||||
        isOnline={config.online}
 | 
			
		||||
        onClick={() => dispatcConfig({ type: 'toggleOnline' })}
 | 
			
		||||
      />
 | 
			
		||||
 | 
			
		||||
      <nav>
 | 
			
		||||
@ -64,11 +71,11 @@ function Header({ pollingReducer }) {
 | 
			
		||||
        </NavLink>
 | 
			
		||||
 | 
			
		||||
        <NavLink to='/games'>
 | 
			
		||||
          <Wobler text="Games" dance={polling.games} />
 | 
			
		||||
          <Wobler text="Games" dance={isPolling.games} />
 | 
			
		||||
        </NavLink>
 | 
			
		||||
 | 
			
		||||
        <NavLink to='/leaderboard'>
 | 
			
		||||
          <Wobler text='Leaderboard' dance={polling.leaderboard} />
 | 
			
		||||
          <Wobler text='Leaderboard' dance={isPolling.leaderboard} />
 | 
			
		||||
        </NavLink>
 | 
			
		||||
      </nav>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@ -1,26 +1,29 @@
 | 
			
		||||
import usePolling from '../hook/Polling';
 | 
			
		||||
 | 
			
		||||
export default function useGamesApi(dispatchGames) {
 | 
			
		||||
export default function useGamesApi(gamesReducer, config) {
 | 
			
		||||
    const [games, dispatchGames] = gamesReducer;
 | 
			
		||||
 | 
			
		||||
    const useList = (pollingReducer) => {
 | 
			
		||||
        const [polling, dispatchPolling] = pollingReducer;
 | 
			
		||||
 | 
			
		||||
        const onResponce = (json) => {
 | 
			
		||||
            dispatchGames({ type: 'next', list: json });
 | 
			
		||||
    const usePollingGamesList = () => {
 | 
			
		||||
        const onSuccess = (gamesList) => {
 | 
			
		||||
            dispatchGames({ type: 'next', gamesList });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const mode = (polling.enabled === true)
 | 
			
		||||
            ? { interval_sec: 30 }      // fetch gamesList every half a minue
 | 
			
		||||
            : { interval_stop: true }   // user has fliped OfflineToggel
 | 
			
		||||
        const isPollingGamesList = usePolling('/api/games', onSuccess, config.intervalMode(30));
 | 
			
		||||
        if (games.isPollingGamesList !== isPollingGamesList) {
 | 
			
		||||
            dispatchGames({ type: 'next', isPollingGamesList });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const isPolling = usePolling('/api/games', onResponce, mode);
 | 
			
		||||
        return games;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        if (isPolling !== polling.games) {
 | 
			
		||||
            dispatchPolling({ type: 'next', games: isPolling });
 | 
			
		||||
    const usePushNewGame = () => {
 | 
			
		||||
        const onSuccess = (game) => {
 | 
			
		||||
            dispatchGames({ type: 'next', game });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        list: useList
 | 
			
		||||
        pollGamesList: usePollingGamesList,
 | 
			
		||||
        pushNewGame: usePushNewGame
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,26 +1,22 @@
 | 
			
		||||
import { useState } from "react";
 | 
			
		||||
import usePolling from "../hook/Polling";
 | 
			
		||||
 | 
			
		||||
export default function useLeaderboardApi() {
 | 
			
		||||
    const [leaderboard, setLeaderboard] = useState(null);
 | 
			
		||||
export default function useLeaderboardApi(leaderboardReducer, config) {
 | 
			
		||||
    const [leaderboard, dispatchLeaderboard] = leaderboardReducer;
 | 
			
		||||
 | 
			
		||||
    const usePoll = (pollingReducer) => {
 | 
			
		||||
        const [polling, dispatchPolling] = pollingReducer;
 | 
			
		||||
    const usePollingTable = () => {
 | 
			
		||||
        const onSuccess = (table) => {
 | 
			
		||||
            dispatchLeaderboard({ type: 'next', table });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const mode = (polling.enabled === true)
 | 
			
		||||
            ? { interval_sec: 300 }     // update leaderbord stats every 5 min
 | 
			
		||||
            : { interval_stop: true }   // user has fliped OfflineToggel
 | 
			
		||||
 | 
			
		||||
        const isPolling = usePolling('/api/leaderboard', setLeaderboard, mode);
 | 
			
		||||
 | 
			
		||||
        if (isPolling !== polling.leaderboard) {
 | 
			
		||||
            dispatchPolling({ type: 'next', leaderboard: isPolling });
 | 
			
		||||
        const isPollingTable = usePolling('/api/leaderboard', onSuccess, config.intervalMode(300));
 | 
			
		||||
        if (leaderboard.isPollingTable !== isPollingTable) {
 | 
			
		||||
            dispatchLeaderboard({ type: 'next', isPollingTable });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return leaderboard;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        poll: usePoll
 | 
			
		||||
        pollTable: usePollingTable
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,20 +1,19 @@
 | 
			
		||||
import usePolling from "../hook/Polling";
 | 
			
		||||
import useUserReducer from "../reducer/user";
 | 
			
		||||
 | 
			
		||||
export default function useUserApi() {
 | 
			
		||||
    const [user, dispatchUser] = useUserReducer();
 | 
			
		||||
export default function useUserApi(userReducer) {
 | 
			
		||||
    const [user, dispatchUser] = userReducer;
 | 
			
		||||
 | 
			
		||||
    const useGet = () => {
 | 
			
		||||
        const onResponce = (json) => {
 | 
			
		||||
            dispatchUser({ type: "parse", json });
 | 
			
		||||
    const useGetUser = () => {
 | 
			
		||||
        const onSuccess = (userJson) => {
 | 
			
		||||
            dispatchUser({ type: "parse", userJson });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        usePolling('/api/user', onResponce); // <<-- fetch once
 | 
			
		||||
        usePolling('/api/user', onSuccess); // <<-- fetch once
 | 
			
		||||
 | 
			
		||||
        return user;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        get: useGet
 | 
			
		||||
        getUser: useGetUser
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -19,7 +19,8 @@ import GameBoard from './games/GameBoard';
 | 
			
		||||
 | 
			
		||||
import './Games.css';
 | 
			
		||||
 | 
			
		||||
export default function Games({ context: { games, dispatchGames, gamesApi }, players }) {
 | 
			
		||||
export default function Games({ context: { gamesReducer, gamesApi }, players }) {
 | 
			
		||||
  const [games, dispatchGames] = gamesReducer;
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <GamesContext.Provider value={games} >
 | 
			
		||||
 | 
			
		||||
@ -4,13 +4,12 @@ import Loading from '../components/Loading';
 | 
			
		||||
 | 
			
		||||
export default function Leaderboard({ players }) {
 | 
			
		||||
 | 
			
		||||
  const leaderboard = players.leaderboard;
 | 
			
		||||
 | 
			
		||||
  if (leaderboard == null)
 | 
			
		||||
  const table = players.leaderboard.table;
 | 
			
		||||
  if (table == null)
 | 
			
		||||
    return <Loading />
 | 
			
		||||
 | 
			
		||||
  const tableRows = Object.keys(leaderboard).map(playerName => {
 | 
			
		||||
    var rank = leaderboard[playerName];
 | 
			
		||||
  const tableRows = Object.keys(table).map(playerName => {
 | 
			
		||||
    var rank = table[playerName];
 | 
			
		||||
 | 
			
		||||
    return <tr key={playerName} className={players.isCurrentUser(playerName) && 'currentuser'}>
 | 
			
		||||
      <td>{playerName}</td>
 | 
			
		||||
 | 
			
		||||
@ -4,13 +4,13 @@ import Wobler from '../../../components/Wobler';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export default function Create({ isCurrentUser }) {
 | 
			
		||||
export default function Create({ isCurrentUser, onClick }) {
 | 
			
		||||
    const newGameCtx = useContext(GamesContext).newGame;
 | 
			
		||||
 | 
			
		||||
    const hasPlayers = checkPlayers(newGameCtx);
 | 
			
		||||
    const hasCurrentUser = checkCurrentUser(newGameCtx, isCurrentUser);
 | 
			
		||||
 | 
			
		||||
    const pushNewGame = () => {
 | 
			
		||||
    const prepareRequest = () => {
 | 
			
		||||
        if (!hasPlayers)
 | 
			
		||||
            return alert("Black and White players must be selected for the game");
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,7 @@ export default function Create({ isCurrentUser }) {
 | 
			
		||||
        if (newGameCtx.pushing)
 | 
			
		||||
            return; // current request is still being processed
 | 
			
		||||
 | 
			
		||||
        //onClick
 | 
			
		||||
        console.log("send request");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -27,7 +28,7 @@ export default function Create({ isCurrentUser }) {
 | 
			
		||||
        <button className={'Create'
 | 
			
		||||
            + (hasPlayers && hasCurrentUser ? ' ready' : '')
 | 
			
		||||
        }
 | 
			
		||||
            onClick={pushNewGame}
 | 
			
		||||
            onClick={prepareRequest}
 | 
			
		||||
        >
 | 
			
		||||
            <Wobler text="Create" dance={newGameCtx.pushing} />
 | 
			
		||||
        </button>
 | 
			
		||||
 | 
			
		||||
@ -7,14 +7,14 @@ import Loading from '../../../components/Loading';
 | 
			
		||||
 | 
			
		||||
export default function GameSelector({ yours, opponents, onClick }) {
 | 
			
		||||
 | 
			
		||||
    const games = useContext(GamesContext);
 | 
			
		||||
    if (games.list === null)
 | 
			
		||||
    const gamesList = useContext(GamesContext).gamesList;
 | 
			
		||||
    if (gamesList === null)
 | 
			
		||||
        return <Loading />
 | 
			
		||||
 | 
			
		||||
    const yoursList = games.list.filter(game => game.status === yours)
 | 
			
		||||
    const yoursList = gamesList.filter(game => game.status === yours)
 | 
			
		||||
        .map(game => <Selectable game={game} key={game.uuid} onClick={onClick} />)
 | 
			
		||||
 | 
			
		||||
    const opponentsList = games.list.filter(game => game.status === opponents)
 | 
			
		||||
    const opponentsList = gamesList.filter(game => game.status === opponents)
 | 
			
		||||
        .map(game => <Selectable game={game} key={game.uuid} onClick={onClick} />)
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
 | 
			
		||||
@ -11,9 +11,9 @@ export default function NewGame({ players, onSelectPlayer }) {
 | 
			
		||||
    /*
 | 
			
		||||
     * Name options
 | 
			
		||||
     */
 | 
			
		||||
    const nameOptions = !players.leaderboard
 | 
			
		||||
    const nameOptions = !players.leaderboard.table
 | 
			
		||||
        ? [<option key='loading' value='…'>…loading</option>]
 | 
			
		||||
        : Object.keys(players.leaderboard).map(playerName =>
 | 
			
		||||
        : Object.keys(players.leaderboard.table).map(playerName =>
 | 
			
		||||
            <option key={playerName} value={playerName}>
 | 
			
		||||
                {players.isCurrentUser(playerName) ? 'You' : playerName}
 | 
			
		||||
            </option>)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										44
									
								
								webapp/src/reducer/config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								webapp/src/reducer/config.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
import { useReducer } from 'react';
 | 
			
		||||
import { namedLocalStorage } from '../util/PersistentStorage';
 | 
			
		||||
import { nextState } from '../util/StateHelper';
 | 
			
		||||
 | 
			
		||||
const Persistent = (() => {
 | 
			
		||||
  const [getOnline, setOnline] = namedLocalStorage('config.online', true);
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    getOnline,
 | 
			
		||||
    setOnline
 | 
			
		||||
  }
 | 
			
		||||
})(); // <<--- Execute
 | 
			
		||||
 | 
			
		||||
const initialState = {
 | 
			
		||||
  online: Persistent.getOnline() === 'true',
 | 
			
		||||
 | 
			
		||||
  intervalMode
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function dispatch(state, action) {
 | 
			
		||||
  switch (action.type) {
 | 
			
		||||
 | 
			
		||||
    case 'toggleOnline': return {
 | 
			
		||||
      ...state,
 | 
			
		||||
      online: Persistent.setOnline(!state.online)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    case 'next':
 | 
			
		||||
      return nextState(state, action);
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      throw Error('ConfigReducer: unknown action.type', action.type);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function useConfigReducer() {
 | 
			
		||||
  return useReducer(dispatch, initialState);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function intervalMode(interval_sec) {
 | 
			
		||||
  return (this.online === true)
 | 
			
		||||
    ? { interval_sec }          // fetch from API every interval_sec
 | 
			
		||||
    : { interval_stop: true }   // user has fliped OfflineToggel
 | 
			
		||||
}
 | 
			
		||||
@ -1,16 +1,20 @@
 | 
			
		||||
import { useReducer } from 'react';
 | 
			
		||||
import { nextState } from '../util/StateHelper';
 | 
			
		||||
 | 
			
		||||
export const gamesInitialState = {
 | 
			
		||||
  list: null,
 | 
			
		||||
const initialState = {
 | 
			
		||||
  gamesList: null,
 | 
			
		||||
 | 
			
		||||
  newGame: {
 | 
			
		||||
    whitePlayer: '',
 | 
			
		||||
    blackPlayer: ''
 | 
			
		||||
  }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // Network
 | 
			
		||||
  isPollingGamesList: false,
 | 
			
		||||
  isPushingNewGame: false,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function gamesReducer(state, action) {
 | 
			
		||||
function reducer(state, action) {
 | 
			
		||||
  switch (action.type) {
 | 
			
		||||
 | 
			
		||||
    case 'next':
 | 
			
		||||
@ -22,5 +26,5 @@ export function gamesReducer(state, action) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function useGamesReducer() {
 | 
			
		||||
  return useReducer(gamesReducer, gamesInitialState);
 | 
			
		||||
  return useReducer(reducer, initialState);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								webapp/src/reducer/leaderboard.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								webapp/src/reducer/leaderboard.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
import { useReducer } from 'react';
 | 
			
		||||
import { nextState } from '../util/StateHelper';
 | 
			
		||||
 | 
			
		||||
const initialState = {
 | 
			
		||||
  table: null,
 | 
			
		||||
 | 
			
		||||
  // Network
 | 
			
		||||
  isPollingTable: false
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function reducer(state, action) {
 | 
			
		||||
  switch (action.type) {
 | 
			
		||||
 | 
			
		||||
    case 'next':
 | 
			
		||||
      return nextState(state, action);
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      throw Error('LeaderboardReducer: unknown action.type', action.type);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function useLeaderboardReducer() {
 | 
			
		||||
  return useReducer(reducer, initialState);
 | 
			
		||||
}
 | 
			
		||||
@ -1,39 +0,0 @@
 | 
			
		||||
import { useReducer } from 'react';
 | 
			
		||||
import { namedLocalStorage } from '../util/PersistentStorage';
 | 
			
		||||
import { nextState } from '../util/StateHelper';
 | 
			
		||||
 | 
			
		||||
const Persistent = (() => {
 | 
			
		||||
  const [getEnabled, setEnabled] = namedLocalStorage('polling.enabled', true);
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    getEnabled,
 | 
			
		||||
    setEnabled
 | 
			
		||||
  }
 | 
			
		||||
})(); // <<--- Execute
 | 
			
		||||
 | 
			
		||||
export const pollingInitialState = {
 | 
			
		||||
  enabled: Persistent.getEnabled() === 'true',
 | 
			
		||||
 | 
			
		||||
  games: false,
 | 
			
		||||
  leaderboard: false
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function pollingReducer(curntState, action) {
 | 
			
		||||
  switch (action.type) {
 | 
			
		||||
 | 
			
		||||
    case 'toggleOnOff': return {
 | 
			
		||||
      ...curntState,
 | 
			
		||||
      enabled: Persistent.setEnabled(!curntState.enabled)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    case 'next':
 | 
			
		||||
      return nextState(curntState, action);
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      throw Error('Unknown action.type:' + action.type);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function usePollingReducer() {
 | 
			
		||||
  return useReducer(pollingReducer, pollingInitialState);
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { useReducer } from 'react';
 | 
			
		||||
import { localeCompare } from '../util/Locale';
 | 
			
		||||
 | 
			
		||||
export const userInitialState = {
 | 
			
		||||
const initialState = {
 | 
			
		||||
  username: '',
 | 
			
		||||
 | 
			
		||||
  isCurrentUser: function (otherUsername) {
 | 
			
		||||
@ -9,13 +9,13 @@ export const userInitialState = {
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function userReducer(state, action) {
 | 
			
		||||
function reducer(state, action) {
 | 
			
		||||
  switch (action.type) {
 | 
			
		||||
 | 
			
		||||
    case 'parse':
 | 
			
		||||
      return {
 | 
			
		||||
        ...state,
 | 
			
		||||
        username: action.json.username
 | 
			
		||||
        username: action.userJson.username
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
@ -24,5 +24,5 @@ export function userReducer(state, action) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function useUserReducer() {
 | 
			
		||||
  return useReducer(userReducer, userInitialState);
 | 
			
		||||
  return useReducer(reducer, initialState);
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user