上下文更改后 ReactJS 不重新渲染

ReactJS not re-rendering after context changed

我这里有一个基本应用程序,我正在尝试正确配置 React Context,但它无法正常工作。我的目标是在 React 上下文中使用 currentStage 的内容呈现 PlayScreenGame 更改上下文,但 App 继续使用“welcome”字符串而不是“won”呈现 PlayScreen ”或“丢失”。

此外,我知道 gameContext.js 用于自动完成,但我在那里添加了“欢迎”以获得第一个默认状态。当 App 首次呈现时,我无法找到设置第一个“欢迎”上下文的方法。

我尝试用上下文本身喂 PlayScreen 但没有用,现在我尝试用它设置状态但它也不起作用(即使使用 useEffect并将上下文作为依赖项)。

所以我有两个问题,我做错了什么?而且,我设置“欢迎”默认状态的方式是错误的?如果是这样,我该怎么做?谢谢。

gameContext.js

import React from 'react';

const GameContext = React.createContext({
  currentStage: 'welcome',
  playerStage: (stage) => {},
});

export default GameContext;

GameProvider.jsx

import React, { useReducer, useMemo } from 'react';
import PropTypes from 'prop-types';
import GameContext from './gameContext';

const defaultState = {
  currentStage: '',
};

const gameReducer = (state, action) => {
  if (action.type === 'STAGE') {
    return {
      currentStage: action.playerStage,
    };
  }

  return defaultState;
};

const GameProvider = ({ children }) => {
  const [gameState, dispatchGameAction] = useReducer(gameReducer, defaultState);

  const playerStageHandler = (playerStage) => {
    dispatchGameAction({
      type: 'STAGE',
      playerStage,
    });
  };

  const gameContext = useMemo(
    () => ({
      currentStage: gameState.currentStage,
      playerStage: playerStageHandler,
    }),
    [gameState.currentStage]
  );

  return (
    <GameContext.Provider value={gameContext}>{children}</GameContext.Provider>
  );
};

GameProvider.propTypes = {
  children: PropTypes.node.isRequired,
};

export default GameProvider;

App.jsx

import React, { useContext, useState, useEffect } from 'react';
import GameProvider from './store/GameProvider';
import GameContext from './store/gameContext';
import PlayScreen from './components/PlayScreen';
import Settings from './components/Settings';
import Game from './components/Game';

const App = () => {
  const gameContext = useContext(GameContext);
  const [stage, setStage] = useState(gameContext.currentStage);

  useEffect(() => {
    setStage(gameContext.currentStage);
  }, [gameContext]);

  const [currentScreen, setCurrentScreen] = useState({
    playScreen: true,
    settings: false,
    game: false,
  });

  const changeScreenHandler = (newScreen) => {
    switch (newScreen) {
      case 'playScreen':
        setCurrentScreen({
          playScreen: true,
          settings: false,
          game: false,
        });
        break;
      case 'settings':
        setCurrentScreen({
          playScreen: false,
          settings: true,
          game: false,
        });
        break;
      case 'game':
        setCurrentScreen({
          playScreen: false,
          settings: false,
          game: true,
        });
        break;
      default:
        break;
    }
  };

  return (
    <GameProvider>
      {currentScreen.playScreen && (
        <PlayScreen stage={stage} onChangeScreen={changeScreenHandler} />
      )}
      {currentScreen.settings && (
        <Settings onChangeScreen={changeScreenHandler} />
      )}
      {currentScreen.game && <Game onChangeScreen={changeScreenHandler} />}
    </GameProvider>
  );
};

export default App;

PlayScreen.jsx

import PropTypes from 'prop-types';

const PlayScreen = ({ stage, onChangeScreen }) => {
  const clickHandler = () => {
    onChangeScreen('settings');
  };

  return (
    <div>
      <h1>{stage}</h1>
      <button type="button" onClick={clickHandler}>
        Go
      </button>
    </div>
  );
};

PlayScreen.propTypes = {
  stage: PropTypes.string.isRequired,
  onChangeScreen: PropTypes.func.isRequired,
};

export default PlayScreen;

Game.jsx

import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import GameContext from '../store/gameContext';

const Game = ({ onChangeScreen }) => {
  const gameContext = useContext(GameContext);

  const wonHandler = () => {
    onChangeScreen('playScreen');
    gameContext.playerStage('won');
  };

  const lostHandler = () => {
    onChangeScreen('playScreen');
    gameContext.playerStage('lost');
  };

  return (
    <div>
      <h1>GAME RUNNING</h1>
      <button type="button" onClick={wonHandler}>
        won
      </button>
      <button type="button" onClick={lostHandler}>
        lost
      </button>
    </div>
  );
};

Game.propTypes = {
  onChangeScreen: PropTypes.func.isRequired,
};

export default Game;

您正在使用 GameProvider 之上的 GameContext。上下文不应该可用,因为 GameProvider 未向 App 提供上下文。

尝试将 GameProvider 下的所有内容移动到它自己的组件中并在那里使用上下文。