问题
I am having an issue when deploying my React application to Firebase. The "/"
route returns a blank page as shown here:
The "/play"
route is working when deployed.
The application works locally, and this old post is very similar. I think the problem is related to how the Routing is set up.
Index.json:
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import * as serviceWorker from "./serviceWorker";
import "bootstrap/dist/css/bootstrap.min.css";
import "font-awesome/css/font-awesome.min.css";
import "../node_modules/font-awesome/css/font-awesome.min.css";
import Landing from "./Landing";
import Startpage from "./Startpage/Startpage";
import { createStore, applyMiddleware } from "redux";
import rootReducer from "./Reducers/Reducers";
import { Provider } from "react-redux";
import { composeWithDevTools } from "redux-devtools-extension";
import promiseMiddleware from "redux-promise";
import { compose } from "redux";
import thunk from "redux-thunk";
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
function configureStore(preloadedState) {
return createStore(
rootReducer,
composeEnhancer(applyMiddleware(thunk, promiseMiddleware))
);
}
const store = configureStore();
ReactDOM.render(
<Provider store={store}>
<React.StrictMode>
<Landing />
</React.StrictMode>
</Provider>,
document.getElementById("root")
);
serviceWorker.unregister();
Landing.js
import React, { Component } from "react";
import App from "./App";
import Rules from "./Rules/Rules";
import { Router, Switch, Route } from "react-router-dom";
import Startpage from "./Startpage/Startpage";
import history from "./history.js";
class Landing extends Component {
render() {
return (
<Router history={history}>
<Switch>
<Route exact path="/" component={Startpage} />
<Route exact path="/rules" component={Rules} />
<Route exact path="/play" component={App} />
</Switch>
</Router>
);
}
}
export default Landing;
Startpage.js
import React, { Component } from "react";
import { NavLink } from "react-router-dom";
import "./Startpage.css";
import firebase from "firebase/app";
import TextField from "@material-ui/core/TextField";
import { makeStyles } from "@material-ui/core/styles";
import { connect } from "react-redux";
import { compose } from "redux";
import { setGameId, setGameId1, updateState } from "../Actions/Actions";
import Button from "@material-ui/core/Button";
import { DB_CONFIG } from "../Config/config";
import history from "../history.js";
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
flexWrap: "wrap",
},
textField: {
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
width: "25ch",
},
}));
class Startpage extends Component {
constructor(props) {
super(props);
this.state = {
gameObj: { key: null, gameId: null },
testing: false,
newWordContent: "",
};
if (!firebase.apps.length) {
firebase.initializeApp(DB_CONFIG);
}
firebase.database.enableLogging(false);
this.gameIds = firebase.database().ref().child("gameIds");
}
getLargestGameIdInDb = () => {
var myPromise = new Promise((resolve, reject) => {
this.gameIds
.orderByChild("gameId")
.limitToLast(1)
.once("value", function (snap) {
snap.forEach((child) => {
let filteredObj = child.val().gameId;
console.log(child.val().gameId);
resolve(filteredObj);
});
});
});
return myPromise;
};
handleNewGame = async () => {
// Function fired when new game button is pressed!
let a = await this.checkIfEmptyDb();
if (a === false) {
this.sendNew(0, this.handleState); // setting the new game id to 0.
}
if (a === true) {
console.log("The db exists!");
try {
this.updateAndSendNew(this.sendNew);
} catch (e) {
console.log("Make sure word is filled in");
}
}
};
checkIfEmptyDb = async () => {
var ref = firebase.database().ref("gameIds");
// Return value of the promise
return ref.once("value").then((snapshot) => {
const a = snapshot.exists();
return a;
});
};
// callback func
updateAndSendNew = async (callback) => {
this.getLargestGameIdInDb().then((newId) => {
let newGameId = newId + 1; // adding one to the larges gameId in the db
callback(newGameId, this.handleState);
});
};
sendNew = async (newId, callback) => {
await callback(newId); // This is completed first before routing to the playing app.
//this.routingFunction();
};
handleState = async (newId) => {
try {
var newRef = this.gameIds.push();
var newKey = newRef.key;
console.log(newKey, newId);
newRef.set({ gameId: newId }).then(() => {
console.log("add to redux state!");
this.props.changeGlobalId2(newId, newKey); // updating store, is slow.
this.setState(
{
testing: true,
gameObj: {
gameId: newId,
key: newKey,
},
},
() => {
console.log("New state:", this.state);
}
);
});
} catch (e) {
console.log("Game update not pushed to firebase");
}
};
// I need to make sure this one is called after all those other ones!
routingFunction = () => {
this.props.history.push("/play");
};
handleUserInput = (e) => {
this.setState({ newWordContent: e.target.value });
};
joinGame = () => {
console.log(this.state.newWordContent); // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch
this.getMatchingGameKey(this.state.newWordContent)
.then((res) => {
console.log("key", res.key);
console.log("gameId", res.val().gameId);
this.setState({ newWordContent: "" });
this.props.changeGlobalId2(res.val().gameId, res.key); // update redux state.
})
.catch((error) => {
// Game ID does not exist in db.
alert("Game PIN does not exist ");
});
// compare the gameID with the db
};
getMatchingGameKey = (gameId) => {
var myPromise = new Promise((resolve, reject) => {
//let ref = firebase.database().ref().child("gameIds").child("gameId");
this.gameIds
.orderByChild("gameId")
.equalTo(parseInt(gameId, 10))
.on("value", function (snapshot) {
if (snapshot.val() == null) {
reject(Error("GameId does not exist!"));
} else {
snapshot.forEach(function (data) {
resolve(data); // passing on
//console.log(data.key);
});
}
});
});
return myPromise;
};
render() {
return (
<div className="wrapper">
<div>
<header className="main-header">
<div className="container">
<h1 className="mh-logo">Chapi-chapau</h1>
<nav className="main-nav">
<ul className="main-nav-list"></ul>
</nav>
</div>
</header>
</div>
<div className="container">
<div className="join">
<div>Join existing game</div>
<div className="column">
<TextField
id="outlined-full-width"
value={this.state.newWordContent}
style={{ margin: 8 }}
placeholder="GAME PIN + ENTER"
helperText="Full width!"
margin="normal"
InputLabelProps={{
shrink: true,
}}
variant="outlined"
onChange={this.handleUserInput}
/>
<Button
id="outlined-button"
variant="outlined"
onClick={this.joinGame}
>
Join game
</Button>
</div>
</div>
<div className="new">
<div>Generate new game pin</div>
<Button
id="outlined-button"
variant="outlined"
onClick={this.handleNewGame}
>
Create game PIN
</Button>
</div>
</div>
</div>
);
}
}
function mapStateToProps(state) {
console.log("mapStateToProps", state);
return {
globalGameId: state.globalGameId,
globalGameKey: state.globalGameKey,
};
}
function mapDispatchToProps(dispatch) {
return {
changeGlobalId2: (id, gameKey) => {
dispatch(updateState(id, gameKey)).then(() => {
history.push("/play");
});
},
};
}
export default compose(connect(mapStateToProps, mapDispatchToProps))(Startpage);
firebase.json:
{
"database": {
"rules": "database.rules.json"
},
"hosting": {
"public": "build",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
],
"headers": [
{"source": "/service-worker.js", "headers": [{"key": "Cache-Control", "value": "no-cache"}]}
]
}
}
Project structure:
.
├── README.md
├── build
│ ├── 404.html
│ ├── asset-manifest.json
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ ├── precache-manifest.854d50eae40e11026f38a5efaaf2e505.js
│ ├── robots.txt
│ ├── service-worker.js
│ └── static
├── database.rules.json
├── firebase.json
├── package-lock.json
├── package.json
├── public
│ ├── 404.html
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── Actions
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── Config
│ ├── Images
│ ├── Landing.js
│ ├── Modal
│ ├── Navbar
│ ├── Reducers
│ ├── Rules
│ ├── Startpage
│ ├── Word
│ ├── WordForm
│ ├── Wordpool
│ ├── history.js
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ ├── serviceWorker.js
│ └── setupTests.js
└── yarn.lock
Output after building:
The project was built assuming it is hosted at /.
You can control this with the homepage field in your package.json.
History.js
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
export default history;
Thanks!
来源:https://stackoverflow.com/questions/61154061/react-and-firebase-routing-issue-blank-screen