最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - page doesn't load on refresh - react-router-dom - Stack Overflow

programmeradmin0浏览0评论

I have basic react app with the following pages: Home, Profile, contact, and experience. I have set up the routes for each page but when I go to a different page other than home, it renders but when I refresh page, the page doesn't load.

I noticed if I add the # before the page name, for example http://localhost:1234/#/profile the page renders. So i'm confused why I need to the # which I don't want and I'm using react-router-dom, so there is no need for #.

I added the historyApiFallback to my webpack.config but that doesn't work. Can anyone help me with this? I'm new to react and I want to learn as much as possible. Your help will be appreciated!

App.jsx

import React, { Component } from "react";
import Navbar from "./ponents/navbar";
import Intro from "./ponents/introPage";
import Experience from "./ponents/experiencePage";
import Profile from "./ponents/profilePage";
import Contact from "./ponents/contactPage";
import { BrowserRouter as Router, Link, Route } from 'react-router-dom';

class App extends Component {
    render(){
        return (
            <Router>
                <div className="pageSections">
                    <Navbar />
                    <div className="navContent">
                        <Route exact path="/" ponent={Intro}/>
                        <Route path="/experience" ponent={Experience}/>
                        <Route path="/profile" ponent={Profile}/>
                        <Route path="/contact" ponent={Contact}/>
                    </div>
                </div>
            </Router>
        );
    }
}

export default App;

navbar.jsx

import React, { Component } from "react";
import { Link } from "react-router-dom";

class Navbar extends Component {
    render(){
        return (

            <div className="navFrame">
                <Link to="/">
                    <div className="topNav"><div className="navBar"><h3>Marteen</h3></div></div>
                </Link>

                <Link to="/profile">
                    <div className="rightNav"><div className="navBar"><h3>Profile</h3></div></div>
                </Link>

                <Link to="/experience">
                    <div className="bottomNav"><div className="navBar"><h3>Experience</h3></div></div>
                </Link>

                <Link to="/contact">
                    <div className="leftNav"><div className="navBar"><h3>Contact</h3></div></div>
                </Link>
            </div>

        );
    }
}

export default Navbar;

webpack.config.js

const webpack = require('webpack');
const config = {
    entry:  __dirname + '/js/index.jsx',
    output: {
        path: __dirname + '/dist',
        filename: 'bundle.js',
    },
    resolve: {
        extensions: ['.js', '.jsx', '.css']
    },
    module: {
      rules: [
        {
          test: /\.jsx?/,
          exclude: /node_modules/,
          use: 'babel-loader'
        },
        {
          test: /\.scss?/,
          loader: 'style-loader!css-loader!sass-loader' 
        }
      ]
    },
    devServer: {
        historyApiFallback: true,
        contentBase: './',
        hot: true
    }
};
module.exports = config;

package.json

{
  "main": "index.js",
  "scripts": {
    "build": "webpack -p --progress --config webpack.config.js",
    "dev-build": "webpack --progress -d --config webpack.config.js",
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "webpack --progress -d --config webpack.config.js --watch",
    "start": "npm run open",
    "open": "concurrently \"http-server -a localhost -p 1234\" \"open http://localhost:1234\""
  },

  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.4",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-react": "^6.24.1",
    "concurrently": "^3.6.1",
    "css-loader": "^0.28.11",
    "http-server": "^0.11.1",
    "node-sass": "^4.7.2",
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "react-router": "^4.2.0",
    "react-router-dom": "^4.2.2",
    "sass-loader": "^6.0.7",
    "style-loader": "^0.20.3",
    "webpack": "^4.1.1",
    "webpack-cli": "^2.0.12"
  },
  "dependencies": {
    "npm": "^5.10.0"
  }
}

Update

package.json

{
  "name": "fullstack_profile",
  "version": "1.0.0",
  "description": "fullstack profile with flask and react",
  "main": "index.js",
  "scripts": {
    "build": "webpack -p --progress --config webpack.config.js",
    "dev-build": "webpack --progress -d --config webpack.config.js",
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "webpack-dev-server --hot --progress --mode development",
    "start": "npm run open",
    "open": "concurrently \"http-server -a localhost -p 1234\" \"open http://localhost:1234\""
  },
  "repository": {
    "type": "git",
    "url": "git+.git"
  },
  "author": "martin",
  "babel": {
    "presets": [
      "es2015",
      "react"
    ]
  },
  "license": "ISC",
  "bugs": {
    "url": ""
  },
  "homepage": "",
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.4",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-react": "^6.24.1",
    "concurrently": "^3.6.1",
    "css-loader": "^0.28.11",
    "http-server": "^0.11.1",
    "node-sass": "^4.7.2",
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "react-router": "^4.2.0",
    "react-router-dom": "^4.2.2",
    "sass-loader": "^6.0.7",
    "style-loader": "^0.20.3",
    "webpack": "^4.1.1",
    "webpack-cli": "^2.0.12",
    "webpack-dev-server": "^3.1.5"
  },
  "dependencies": {
    "npm": "^5.10.0"
  }
}

webpack.config

const webpack = require('webpack');
const config = {
    entry:  __dirname + '/js/index.jsx',
    output: {
        path: __dirname + '/dist',
        filename: 'bundle.js',
    },
    resolve: {
        extensions: ['.js', '.jsx', '.css']
    },
    module: {
      rules: [
        {
          test: /\.jsx?/,
          exclude: /node_modules/,
          use: 'babel-loader'
        },
        {
          test: /\.scss?/,
          loader: 'style-loader!css-loader!sass-loader' 
        }
      ]
    },
    devServer: {
      contentBase: __dirname + '/dist',
      press: false,
      port: 1234,
      historyApiFallback: {
        index: 'index.html'
      }
    }
};
module.exports = config;

I have basic react app with the following pages: Home, Profile, contact, and experience. I have set up the routes for each page but when I go to a different page other than home, it renders but when I refresh page, the page doesn't load.

I noticed if I add the # before the page name, for example http://localhost:1234/#/profile the page renders. So i'm confused why I need to the # which I don't want and I'm using react-router-dom, so there is no need for #.

I added the historyApiFallback to my webpack.config but that doesn't work. Can anyone help me with this? I'm new to react and I want to learn as much as possible. Your help will be appreciated!

App.jsx

import React, { Component } from "react";
import Navbar from "./ponents/navbar";
import Intro from "./ponents/introPage";
import Experience from "./ponents/experiencePage";
import Profile from "./ponents/profilePage";
import Contact from "./ponents/contactPage";
import { BrowserRouter as Router, Link, Route } from 'react-router-dom';

class App extends Component {
    render(){
        return (
            <Router>
                <div className="pageSections">
                    <Navbar />
                    <div className="navContent">
                        <Route exact path="/" ponent={Intro}/>
                        <Route path="/experience" ponent={Experience}/>
                        <Route path="/profile" ponent={Profile}/>
                        <Route path="/contact" ponent={Contact}/>
                    </div>
                </div>
            </Router>
        );
    }
}

export default App;

navbar.jsx

import React, { Component } from "react";
import { Link } from "react-router-dom";

class Navbar extends Component {
    render(){
        return (

            <div className="navFrame">
                <Link to="/">
                    <div className="topNav"><div className="navBar"><h3>Marteen</h3></div></div>
                </Link>

                <Link to="/profile">
                    <div className="rightNav"><div className="navBar"><h3>Profile</h3></div></div>
                </Link>

                <Link to="/experience">
                    <div className="bottomNav"><div className="navBar"><h3>Experience</h3></div></div>
                </Link>

                <Link to="/contact">
                    <div className="leftNav"><div className="navBar"><h3>Contact</h3></div></div>
                </Link>
            </div>

        );
    }
}

export default Navbar;

webpack.config.js

const webpack = require('webpack');
const config = {
    entry:  __dirname + '/js/index.jsx',
    output: {
        path: __dirname + '/dist',
        filename: 'bundle.js',
    },
    resolve: {
        extensions: ['.js', '.jsx', '.css']
    },
    module: {
      rules: [
        {
          test: /\.jsx?/,
          exclude: /node_modules/,
          use: 'babel-loader'
        },
        {
          test: /\.scss?/,
          loader: 'style-loader!css-loader!sass-loader' 
        }
      ]
    },
    devServer: {
        historyApiFallback: true,
        contentBase: './',
        hot: true
    }
};
module.exports = config;

package.json

{
  "main": "index.js",
  "scripts": {
    "build": "webpack -p --progress --config webpack.config.js",
    "dev-build": "webpack --progress -d --config webpack.config.js",
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "webpack --progress -d --config webpack.config.js --watch",
    "start": "npm run open",
    "open": "concurrently \"http-server -a localhost -p 1234\" \"open http://localhost:1234\""
  },

  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.4",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-react": "^6.24.1",
    "concurrently": "^3.6.1",
    "css-loader": "^0.28.11",
    "http-server": "^0.11.1",
    "node-sass": "^4.7.2",
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "react-router": "^4.2.0",
    "react-router-dom": "^4.2.2",
    "sass-loader": "^6.0.7",
    "style-loader": "^0.20.3",
    "webpack": "^4.1.1",
    "webpack-cli": "^2.0.12"
  },
  "dependencies": {
    "npm": "^5.10.0"
  }
}

Update

package.json

{
  "name": "fullstack_profile",
  "version": "1.0.0",
  "description": "fullstack profile with flask and react",
  "main": "index.js",
  "scripts": {
    "build": "webpack -p --progress --config webpack.config.js",
    "dev-build": "webpack --progress -d --config webpack.config.js",
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "webpack-dev-server --hot --progress --mode development",
    "start": "npm run open",
    "open": "concurrently \"http-server -a localhost -p 1234\" \"open http://localhost:1234\""
  },
  "repository": {
    "type": "git",
    "url": "git+https://github./medev21/fullstack_profile.git"
  },
  "author": "martin",
  "babel": {
    "presets": [
      "es2015",
      "react"
    ]
  },
  "license": "ISC",
  "bugs": {
    "url": "https://github./medev21/fullstack_profile/issues"
  },
  "homepage": "https://github./medev21/fullstack_profile#readme",
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.4",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-react": "^6.24.1",
    "concurrently": "^3.6.1",
    "css-loader": "^0.28.11",
    "http-server": "^0.11.1",
    "node-sass": "^4.7.2",
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "react-router": "^4.2.0",
    "react-router-dom": "^4.2.2",
    "sass-loader": "^6.0.7",
    "style-loader": "^0.20.3",
    "webpack": "^4.1.1",
    "webpack-cli": "^2.0.12",
    "webpack-dev-server": "^3.1.5"
  },
  "dependencies": {
    "npm": "^5.10.0"
  }
}

webpack.config

const webpack = require('webpack');
const config = {
    entry:  __dirname + '/js/index.jsx',
    output: {
        path: __dirname + '/dist',
        filename: 'bundle.js',
    },
    resolve: {
        extensions: ['.js', '.jsx', '.css']
    },
    module: {
      rules: [
        {
          test: /\.jsx?/,
          exclude: /node_modules/,
          use: 'babel-loader'
        },
        {
          test: /\.scss?/,
          loader: 'style-loader!css-loader!sass-loader' 
        }
      ]
    },
    devServer: {
      contentBase: __dirname + '/dist',
      press: false,
      port: 1234,
      historyApiFallback: {
        index: 'index.html'
      }
    }
};
module.exports = config;

Share Improve this question edited Jul 29, 2018 at 14:49 medev21 asked Jul 27, 2018 at 22:17 medev21medev21 3,05110 gold badges35 silver badges51 bronze badges 2
  • I know gatsby uses localhost:1234 - is that what you're using for this? I didn't think react-router was something you implemented yourself into gatsby - they have a link ponent you can download / install to achieve this. Apologies if I'm miles off. – Jonny Rathbone Commented Jul 27, 2018 at 22:45
  • Have you tried devServer: { contentBase: path.join(__dirname, 'dist'), ... }? – Tholle Commented Jul 27, 2018 at 23:03
Add a ment  | 

2 Answers 2

Reset to default 3

The reason why http://localhost:1234/#/profile works is because # doesn't reload the page. It behaves the same as an anchor tag in HTML where you stay on the same page but scroll to a specific section of it. For example, the below scrolls you to the portfolio section of the page.

<a href="www.page./#portfolio">Portfolio</a>

If you omit the #, this is different. This tells your server to reload the page and visit that location. In your case http://localhost:1234/profile is unknown by the server as you have not specified it on the server side. In these cases, you need to either create the route or proxy the request when the route is not found.

As you are using react-router which is a client-side router, the same file needs to be served by the server and therefore you should go with the proxy option.

When using http-server the docs say you can add the -P or --proxy flag to specify it.

-P or --proxy Proxies all requests which can't be resolved locally to the given url. e.g.: -P http://someurl.

In your case update the below in your package.json.

"open": "concurrently \"http-server -a localhost -p 1234 -P http://localhost:1234\" \"open http://localhost:1234\""

An alternative is to use webpack-dev-server for development. It'll improve your developers experience a lot as it supports hot reloading when a ponent changes.

install it using npm install --save-dev webpack-dev-server

Add the below to your webpack config.

devServer: {
  contentBase: __dirname + '/dist',
  press: false,
  port: 1234,
  historyApiFallback: {
    index: 'index.html' // assuming this is your entry point file that loads your bundle.
  }
},

Then in your package.json add a script for it and run it using npm run watch

"watch": "webpack-dev-server --hot --progress --mode development",

NOTE: Make sure that in your dist folder index.html is present. If it isn't you will run into issues.

I've created a basic project on GitHub so you have a working example.

Solution to Express and at least to Heroku deployment

I want to share my solution that finally allowed the user to access every link in my React App.

After reading these proposed solutions and this helpful article, I could manage to make this works with this following code in my main server.js file:

// Serve static files such as images, CSS files, and JavaScript files for the React frontend app
app.use(express.static(path.join(__dirname, 'client/build')))
// This solves the "Not found" issue when loading an URL other than index.html.
app.get('/*', (req, res) => { //n3
  res.sendFile(path.join(__dirname + '/client/build/index.html'), err => {
    if (err) { res.status(500).send(err) }
  })
})
  • Make sure to always point the path to build which is where all the files are loaded in the production environment.
  • After that, all urls are working well finally!
发布评论

评论列表(0)

  1. 暂无评论