Node.js server overwritten entire DOM with React.JS

只谈情不闲聊 提交于 2020-01-06 17:58:37

问题


What I am trying to do: I am trying to practice MERN structure, so I wanted to set up a node.js server and react front-end first.

However, what happened is that when the server gets fired, the entire DOM got overwrite, why is that?

server.js is a simple node.js

const express = require('express');
const app = express();

// console.log that your server is up and running
app.listen(3000, () => console.log(`Listening on port 3000`));

// create a GET route
app.get('/test', (req, res) => {
  res.send({ express: 'I MADE IT' });
});

React.js is my front-end:

import React from 'react';
import logo from './img/nav-logo.png';
import Product1 from './img/manage.png';
import Product2 from './img/deliver.png';
import Product3 from './img/market.png';
import Service from './service.js'
import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';

class App extends React.Component {
  constructor(props){
    super(props)

    this.state={
      items: [{
          desc:"Manage",
          price: 5000,
          purchased: false,
        },
        {
          desc:"Deliver",
          price: 2000,
          purchased: false,
        },
        {
          desc:"Market",
          price: 4000,
          purchased: false,
        }
      ],
      data:null,
    }
  }

  componentDidMount() {
    console.log("here")
    this.callApi()
      .then(res => this.setState({ data: res.express }))
      .catch(err => console.log(err));
  }

  callApi = async () => {
    const response = await fetch('/test');
    const body = await response.json();

    if (response.status !== 200) throw Error(body.message);

    return body;
  };

  handleClick(desc){
    const newItems = this.state.items.slice()
    this.printItems(newItems)
    for(var item of newItems){
      if(item.desc === desc){
        item.purchased = !item.purchased
      }
    }
    this.printItems(newItems)

    this.setState({
      items: newItems
    })
  }

  printItems(items){
    console.log(items[0].purchased + "  " + items[1].purchased + " " + items[2].purchased)
  }

  render()  {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to Shopping Center</h1>
        </header>
      <div>
        <div>
          {this.state.data}   //<------------trying to render the data here
        </div>
        <Service url={Product1} desc="Manage" alt="MA" purchased={this.state.items[0].purchased} thisClick={ (desc) => this.handleClick("Manage")} />
        <Service url={Product2} desc="Deliver" alt="DE" purchased={this.state.items[1].purchased} thisClick={ (desc) => this.handleClick("Deliver")}/>
        <Service url={Product3} desc="Market" alt="MR" purchased={this.state.items[2].purchased} thisClick={ (desc) => this.handleClick("Market")}/>
      </div>
      </div>
    );
  }
}

export default App;

Without my node.js running, i can render my react just fine. However, once I do npm server.js. localhost:3000 will no longer work. So i treid localhost:3000/test, and the entire HTML became the string "{ express: 'I MADE IT' }"

My index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(<App />, document.getElementById('root'));

I want to render the message as part of my regular React DOM, but somehow the node server overwritten my entire front-end.

Additionally, i got an error message in console state the following:

SyntaxError: Unexpected token < in JSON at position 0
    at App._callee$ (App.js:42)
    at tryCatch (runtime.js:62)
    at Generator.invoke [as _invoke] (runtime.js:296)
    at Generator.prototype.(:3000/anonymous function) [as next] (http://localhost:3000/static/js/bundle.js:31252:21)
    at step (App.css?9a66:26)
    at App.css?9a66:26

The line of code that I located is the componentDidMount() method

My package.json file:

{
  "name": "my-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "bootstrap": "^4.1.3",
    "express": "^4.16.3",
    "react": "^16.5.2",
    "react-dom": "^16.5.2",
    "react-scripts": "1.1.5",
    "reactstrap": "^6.4.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "proxy": "http://localhost:3001"
}

回答1:


For development, given you are using create-react-app for your React application, you can use a development proxy to run both Express and React on separate ports. Any fetch() requests will be redirected to the specified proxy path/port in package.json. This will allow you take advantage of development tools for each platform.

  1. Change the Express server port to anything other than 3000. For example app.listen(3001, () => console.log('Listening on port 3001')); This is so create-react-app can run on 3000 and Express can run on 3001.
  2. Added the following line to the React application's package.json to enable a proxy, "proxy": "http://localhost:3001". A fetch request to /api/test will be redirect to http://localhost:3001/api/test.

For production, given you would want both applications to run on the same port:

  1. Set up static resource loading for the server using static() method.
  2. Added logic to server to redirect all requests that do not match you "API" paths, to load the index.html of the production built npm run build React application using sendFile(). This will allow to use routing within the React application.

Here is what that could look like at a basic level, with the create-react-app build folder generated from npm run build command is placed into path /public/build:

app.use(express.static(path.join(__dirname, 'public', 'build')));

// API route
app.get('/api/test', (req, res) => {
  res.send({ express: 'I MADE IT' });
});

// catch-all route
app.use('*', function (request, response) {
  response.sendFile(path.join(__dirname, 'public', 'build', 'index.html'));
});

React fetch():

// ...
const response = await fetch('/api/test'); // this matches the path specified on server, before the catch all route
const body = await response.json();
// ...

Check out this answer as it was a similar issue.

Update: - Steps to create simple Express + React development environment:

  1. Create Express application using express-generator. Run command npx express-generator react-express
  2. Navigate into created project. Run command cd react-express.
  3. Run command npm install. Then delete directory public.
  4. Create React application using create-react-app. Run command npx create-react-app public.
  5. Install concurrently. Run command npm install concurrently --save-dev.
  6. Edit app.js at the base of project created by express-generator. Add the following lines starting at line 25. This is to expose and endpoint at /api/test and provide a "catch-all" route to load index.html generated by npm run build.

```

app.get('/api/test', (req, res) => {
  res.send({ express: 'I MADE IT' });
});

app.use('*', function (request, response) {
  response.sendFile(path.join(__dirname, 'public', 'build', 'index.html'));
});

```

  1. Edit /bin/www line 15 to change port from 3000 to 3001. var port = normalizePort(process.env.PORT || '3001');
  2. Edit package.json created by create-react-app at /build/package.json. Add the following line "proxy": "http://localhost:3001".
  3. At the base package.json located at the root of the project, created by express-generator, add the following line to srcipts: "dev": "concurrently \"node ./bin/www\" \"cd public && npm start\""
  4. Run command npm run dev from the base of the project. This will load both the server (Express) and client (React) and will proxy calls, in this example /api/test on port 3000 will be directed to the server port running at 3001.

Hopefully that helps!



来源:https://stackoverflow.com/questions/52521509/node-js-server-overwritten-entire-dom-with-react-js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!