React Router / Express / Node - 嵌套动态路由错误

时间:2018-06-12 02:13:05

标签: javascript node.js reactjs react-router-v4 mern

我在页面刷新或直接链接到不使用错误的嵌套URL时遇到常见错误。我没有得到常见的“无法获取”错误,而是得到一个错误“无法读取属性'类型'未定义”。因此,导航到此URL时我的状态数组未定义,例如:

http://localhost:3000/topics/glascow-coma-score

但此请求适用于刷新或直接链接: http://localhost:3000/topics/

编辑:这也是Heroku上的一个实现: https://emquick.herokuapp.com/topics/

https://emquick.herokuapp.com/topics/glascow-coma-score

我已阅读并尝试从这些主题,博客和文档来源实施解决方案:

https://github.com/ReactTraining/react-router/blob/v4.1.1/FAQ.md#why-doesnt-my-application-render-after-refreshing

React router dynamic routes not rendering component

React router: nesting static route within dynamic route refresh error

react-router dynamic segments crash when accessed

Unexpected token < error in react router component

https://tylermcginnis.com/react-router-cannot-get-url-refresh/

我已阅读所有/大部分评论和解决方案 在我的构建文件夹中,捆绑脚本的URL是绝对的,而不是相对的(如上面几个解决方案所建议的那样) 我正按照Tyler McGinnis博客文章的建议在我的服务器上提供通配符索引路由。 我正在使用create-react-app,所以我没有webpack package.json文件。

我并没有超出我的创建反应应用程序来解决这个问题,但在我的搜索中,我没有找到使用create-react-app发布到此问题的任何解决方案,包括任何人建议我必须弹出以解决问题。

这里有一些代码:

Server.js

const bodyParser = require('body-parser'),
      passport = require('passport'),
      mongoose = require('mongoose'),
      express = require('express'),
      dotenv = require('dotenv'),
      morgan = require('morgan'),
      seedDB = require('./seed'),
      path = require('path'),
      cors = require('cors'),
      app = express()

const Resource  = require('./models/resource'),
resources = require('./src/data/resources.json')

//Routes
const resourceRoutes = require('./routes/resources')

//Setup app
dotenv.config()
app.use(morgan('dev'))
app.use(cors())
//app.use(express.static('public'))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: true}))

//SET STATIC ROUTE

// Priority serve any static files.
if (process.env.NODE_ENV === 'production') {
  app.use(express.static(path.resolve(__dirname, 'build')));
} else {
  app.use(express.static('public'))
}

//SERVER & DB
const port = process.env.PORT || 8080
// const db_url = process.env.MONGO_URI
const db_url = process.env.MLAB_URI
mongoose.connect(db_url)

//ROUTES
app.use('/api/resources/', resourceRoutes)

app.get("/*", function (req,res){
  console.log("Index page sent")
  app.get('*', (req, res) => {
    res.sendFile(path.resolve(__dirname, 'index.html'))
  })
})

const server = app.listen(port, function(req,res){
  console.log("EMQuick server started on port " + port + "...")
  console.log(process.env.NODE_ENV)

})

我的resources.js路由文件(这是我的应用程序的json数据来自哪里)

const express= require('express'),
   router = express.Router(),
  Resource = require('../models/resource')

router.get('/', function(req,res){
  Resource.find({}, function (err, resources){
    if (err) console.log(err)
    res.json({resources})
  })
})

router.get('/:id', function(req,res){
  console.log("Im here in the backend API getting " + req.params.id)
  Resource.findById( req.params.id, function (err, resource) {
    if (err) console.log(err)
    // console.log(resource.name)
    res.json({resource})
  })
})


router.post('/', function(req,res){
  console.log(req.body.resource)

  Resource.create(req.body.resource)
    .then(function(newResource) {
      res.status(201).json(newResource)
    })
    .catch(function(err){
      res.send(err)
    })
})



module.exports =router

客户端的我的App.js文件:

import React, {Component} from 'react'
import { Container } from 'semantic-ui-react'
import Navbar from './navigation/Navbar'
// import Home from './pages/Home'
import Categories from './categories/Categories'
import Category from './categories/Category'
import Topics from './topics/Topics'
import Topic from './topics/Topic'
import About from './pages/About'
import NewReference from './new/NewResource'
import * as apiCalls from './api'


import { Route, Switch } from 'react-router-dom'
// import FindArticle from './articles/FindArticle'

let payload = [], allResources  = []

class App extends Component {

  constructor (props) {
    super(props)
    this.state = {
      resources: []
    }

    this.handleSearchChange = this.handleSearchChange.bind(this)
    this.searchResources = this.searchResources.bind(this)
  }


  componentDidMount () {
    this.loadResources()
  }

  async loadResources () {
    payload = await apiCalls.getResources()
    allResources = payload
    console.log(allResources)
    this.setState({resources: allResources.resources})
    console.log(this.state)
  }

  handleSearchChange = (searchText) => {
    console.log(searchText)
    this.setState({
      resources: this.searchResources(searchText)
    })
  }


  searchResources(searchString){
    return allResources.resources.filter((resource) => {
        if (resource.name.toLowerCase().includes(searchString.toLowerCase())) {
          console.log(searchString + " found in " + resource.name + " in Name field ")
          return true
        }
        if (resource.pagebody && resource.pagebody.includes(searchString)) {
          console.log(searchString + " found in " + resource.pagebody + " Pagebody ")

          return true
        }
        if ((resource.description) && resource.description.includes(searchString)){
          console.log(searchString + " found in " + resource.description + " Description ")

          return true
        }
        return false
      }
    )
  }

  render () {

    // const FindTopic = (props) => {
    //   return (
    //     <Topic resources={this.state.resources}
    //            {...props}
    //     />
    //   )
    // }

    return (
      <Container >
        <Navbar
           resources = {this.state.resources}
           handleSearch = {this.handleSearchChange}
        />
        <Switch>
          <Route exact path='/' component={About}/>
          <Route path='/categories/:field'
                 render={(props) => <Category resources={this.state.resources} {...props} />}/>
          <Route path='/categories'
                 render={(props) => <Categories resources={this.state.resources} {...props} />}/>
          <Route path='/new' component={NewReference}/>
          <Route path='/about'
                 render={(props) => <About resources={this.state.resources} {...props} />}/>
          <Route path='/topics/:friendly'
                 render={(props) => <Topic resources={this.state.resources} {...props} />}/>
          <Route path='/topics'
               render={(props) => <Topics resources={this.state.resources} {...props} />}/>

        </Switch>
      </Container>
    )
  }
}


export default App

最后,我的API.js文件带有对我服务器的获取请求:

export async function createResource(resource){
  const postURL = API_URL
  return  fetch(postURL, {
    method: 'post',
    headers: new Headers({
      'Content-Type': 'application/json',
    }),
    body: JSON.stringify({resource: resource})
  })
    .then(resp => {
      if (!resp.ok) {
        if (resp.status >= 400 && resp.status < 500) {
          return resp.json().then(data => {
            let err = {errorMessage: data.message}
            throw err
          })
        } else {
          let err = {errorMessage: 'Please try again later, the server is not responding'}
          throw err
        }
      }
      // console.log(resp.json())
      return resp.json()
    })
}

这似乎是一个常见的错误,我已经尝试了我找到的所有建议,除了我不是直接使用webpack这一事实。如果它像弹出并使用package.json文件中的webpack解决方案一样简单,我也很想尝试,但不想旋转我的轮子。

**不是将通配符/ *路由服务到我的index.html文件解决了单个深度文件(如localhost:3000 / topics)的刷新问题,而不是更深层次的路由。

0 个答案:

没有答案