刷新后无法呈现 React 页面,而是显示原始数据

Unable to render React page after refresh, instead showing raw data

各位!我正在尝试使用 Node/React/Mongoose 构建一个没有 CRA 命令的应用程序,该命令还包括自定义 webpack。

我设法在单个 React 页面中构建所有内容 (App.jsx),但代码看起来很乱。我设法通过首先从数据库中获取数据来构建它,然后围绕它构建所有内容。现在可行了,但我想更进一步。无论获取的数据如何,我都想构建一个应用程序。

现在,我发现自己遇到的问题最好用幻灯片显示。我该如何解决这个问题?我试过更改路径,但没有成功。

进入主页后,正在呈现导航栏。我也可以刷新,它不会坏。

当我使用导航栏导航到 /teacher 时,它会很好地加载所有内容。

但是当我刷新或手动输入 url localhost8080/teacher 时,问题就出现了。它不是组件,而是获取原始数据。

这是我与问题相关的代码:

server.js

app.use('/teacher', authRoutes);
app.use('/class', classRoutes);
app.get('/', (req, res, next) => {
  
  res.sendFile(path.resolve(__dirname, "../docs/index.html"))

})

routes.js

router.get('/signup', authController.teacherList);

控制器

exports.teacherList = (req, res, next) => {
    Teacher.find()
    .then(teacher => {
        return res.send(teacher)
    })
    .catch(err => console.log(err));
}

App.jsx

import React, { Component } from 'react';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import TeacherComponent from './Teacher'
import ClassComponent from './Class'

export default class App extends Component {
    render() {    
      return (
    <Router>
        <div>
          <nav className="navbar navbar-expand-lg navbar-light bg-light">
          <ul className="navbar-nav mr-auto">
          <li><Link to={'/class'} className="nav-link">Class</Link></li>
            <li><Link to={'/teacher'} className="nav-link">Teacher</Link></li>
          </ul>
          </nav>
          <hr />
          <Routes>
              <Route path='/class' element={<ClassComponent />} />
              <Route path='/teacher' element={<TeacherComponent />} />
          </Routes>
        </div>
      </Router>
      );
    }
  }

Teacher.jsx

import React, { Component } from 'react';
import { Redirect } from 'react-router-dom'
import Select from 'react-select';
import 'bootstrap/dist/css/bootstrap.min.css';

class Teacher extends Component {
  
    constructor(props) {
        super(props);
        this.state = {
          teachers: [],
          isSignedUp: false,
          firstName : '',
          lastName: '',
          email: '',
          password: '',
          studentsClass: {
              students: []
          }
        };
      }

      
    componentDidMount() {
        
        fetch('http://localhost:8080/teacher')
          .then(response => response.json())
          .then(teachers => this.setState({teachers: teachers}));
    }

    handleFirstName = (e) => {
        this.setState({firstName: e.target.value});
    }
    handleLastName = (e) => {
        this.setState({lastName: e.target.value});
    }
    handleEmail = (e) => {
        this.setState({email: e.target.value});
    }
    handlePassword = (e) => {
        this.setState({password: e.target.value});
    }

    signUp = () => {
        const requestOptions = {
            method: 'POST',
            headers: {
              Accept: 'application/json',
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({firstName: this.state.firstName , lastName: this.state.lastName, email: this.state.email , password: this.state.password}),
          };
          fetch("/teacher/signup", requestOptions)
          .then((response) => {
            return response.json();
          })
          .then(() => {
                fetch('http://localhost:8080/class')
                .then(response => response.json())
                .then(teachers => this.setState({teachers: teachers}));
          })
          .catch((err) => {
              console.log(err)
          })
    }

    render() {
        // const teachers = this.state.teachers.map(teacher => <div key={teacher._id}>{teacher.firstName} - {teacher.lastName}</div>);
        const teachers = []
        for (let i = 0; i < this.state.teachers.length; i++) {
            teachers.push({label: this.state.teachers[i].firstName + ' ' + this.state.teachers[i].lastName})
        }
        return (
            <div>
            <div className="container">
            <div className="row" style={{marginTop: "100px"}}>
              <div className="col-md-4"></div>
              <div className="col-md-4">
                <Select placeholder="Select teacher"options={ teachers } />
              </div>
              <div className="col-md-4"></div>
              
            </div>
            
          </div>
                        <div></div>
                        <div style={{display: "flex", alignItems: "center", justifyContent: "center", marginTop: "100px"}}><h5>Signup:</h5></div>
                        <div style={{margin: "20px auto", borderTop: "2px solid black", width: "400px", textAlign: "center"}}>
                        <form style={{marginTop: "30px"}} onSubmit={(event) => {
                            event.preventDefault()
                            this.signUp(this.state.teacher)
                        }} >
                                <input style={{textAlign: "center"}} type="text" name="firstName" placeholder="First Name" value={this.state.firstName} onChange={this.handleFirstName} />
                                <div></div>
                                <br></br>
                                <input style={{textAlign: "center"}} type="text" name="lastName" placeholder="Last Name" value={this.state.lastName} onChange={this.handleLastName}/>
                                <div></div>
                                <br></br>
                                <input style={{textAlign: "center"}} type="text" name="email" placeholder="Email" value={this.state.email} onChange={this.handleEmail}/>
                                <div></div>
                                <br></br>
                                <input style={{textAlign: "center"}} type="password" name="password" placeholder="Password" value={this.state.password} onChange={this.handlePassword}/>
                                <div></div>
                                <br></br>
                                <input className="button button2" type="submit" />
                        </form>
                        </div>
                        </div>
        );
      }
}

export default Teacher;

以及代理请求的 webpack:

const webpack = require("webpack");
const path = require("path");

module.exports = {
  entry: path.resolve(__dirname, "./src/index.js"),
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: ["babel-loader"],
      },
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"]
      },
      {
        test: /\.(jpe?g|png|gif|svg)$/i, 
        use: ["file-loader"]
      }
    ],
  },
  resolve: {
    extensions: ["*", ".js", ".jsx"],
  },
  mode: process.env.NODE_ENV,
  output: {
    path: path.resolve(__dirname, "./docs"),
    filename: "bundle.js",
  },
  // [webpack-dev-server] "hot: true" automatically applies HMR plugin, you don't have to add it manually to your webpack configuration.
  plugins: [new webpack.HotModuleReplacementPlugin()],
  devServer: {
    
    // contentBase is deprecated by static in webpack v5
    proxy: {
      '/': 'http://localhost:3000/',
    },
    // contentBase: path.resolve(__dirname, "./docs"),
    hot: true,
  },
};

问题在于您如何配置 server.js 文件

app.use('/teacher', authRoutes);
app.use('/class', classRoutes);
app.get('/', (req, res, next) => {
  
  res.sendFile(path.resolve(__dirname, "../docs/index.html"))

})

现在假设您正在向服务器发送请求以获取 url /teacher 中的数据,现在它正在完美地完成工作。因为,它会遇到第一行并向您发送原始 json 并完成它。

一个解决方案是将所有 api 模块保留在“/api”附加路径中。因此,它们不会与您的常规路由冲突。

app.use('/api/teacher', authRoutes);
app.use('/api/class', classRoutes);
app.get('/', (req, res, next) => {
  
  res.sendFile(path.resolve(__dirname, "../docs/index.html"))

})

这应该可以解决您的问题。

编辑: 最后一条路线应该总是 return 主页。所以,path-matching

需要一颗星
app.get('/*', (req, res, next) => {
  
  res.sendFile(path.resolve(__dirname, "../docs/index.html"))

})

你的服务器是 运行 在本地主机 8080 上,所以客户端可能是 运行 在本地主机上 3030 之类的东西请检查一下,因为我看到你正在调用服务器 api 8080.

你可以这样优化你的代码 -

          <Route path='/class' element={()=><ClassComponent teacher={this.state.teachers} />} />
          <Route path='/teacher' element={()=><TeacherComponent teacher={this.state.teachers/>} />

试试这个,请同时上传 ClassComponent 和 TeacherComponent。