Home > Mobile >  Browser URL changed after POST and PATCH form actions in React - Node app
Browser URL changed after POST and PATCH form actions in React - Node app

Time:03-21

First, I want to apologize for a very long post. I am a beginner and this is a behavior that I am even unsure how to google. I'll try explaining the best way I can.

I am building a simple CRUD app, using Node, Express, React and Mongoose. I started from the back-end and continue towards the front-end. Once I connected the front-end with my back-end, I've noticed an unusual behavior. For example, this is my postEditStudent controller:

exports.postEditStudent = (req, res, next) => {
  console.log(req.params)
  const id = req.params.id;
  console.log('this is body', req.body)
  Student.findByIdAndUpdate(mongoose.Types.ObjectId(id), {firstName : req.body.firstName, lastName : req.body.lastName})
    .then((stud) => {
      console.log('EDIT THIS GUY', stud);
      return res.status(200).redirect('/')
    })
    .catch(err => console.log(err));
}

Now, to get there, we are using a router:

const express = require('express');
const classController = require('../controllers/classController');
const router = express.Router();

router.get('/update/:id', classController.getEditStudent);
router.patch('/update/:id', classController.postEditStudent);

As for my server.js page, this is how it is set-up:

const path = require('path');

const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const cors = require('cors');
const session = require('express-session');

const app = express()
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
  extended: true
}));


app.use(cors())


const classRoutes = require('./routes/class-routes');
const errorController = require('./controllers/error')

const MONGODB_URI = "mongodb srv://this is a mongoose database path"

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

app.use(errorController.get404);


  mongoose
  .connect(MONGODB_URI)
  .then(result => {
    app.listen(3000);
    console.log('CONNECTED')
  })
  .catch(err => {
    console.log(err);
  });

And last, but not the least, react component, where the magic happens:

class App extends Component {
  
    constructor(props) {
        super(props);
        this.state = {
          students: null,
          edit: 'none',
          add: 'block',
          studentId: null,
          firstName: '',
          lastName: ''
        };
      }

  handleFirstNameChange = (e) => {
    this.setState({firstName: e.target.value});
    console.log(this.state.firstName)
 }

 handleLastNameChange = (e) => {
    this.setState({lastName: e.target.value});
 }

  editStudent = id => {
    const requestOptions = {
      method: 'PATCH',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({firstName: this.state.firstName , lastName: this.state.lastName}),
    };
    console.log(id)
    fetch("/class/update/"   id, requestOptions)
    .then((response) => {
        console.log('this is response')
      return response.json();
    })
    .catch((err) => {
        console.log(err)
    })
  }

render() {
        if (!this.state.students) return null;
        const studentNames = this.state.students.map(student => <Draggable bounds="parent" key={student.id}><div className="handle"><img onClick={() => this.getStudent(student.id)} className="imgLogo" src={user} alt="user-logo"/><div></div> {student.firstName}<div></div> {student.lastName}<div></div> <div><div></div><img onClick={() => this.showForm(student.id)} className="imgBox" src={edit} alt="edit-logo"/><img onClick={() => this.deleteStudent(student.id)} className="imgBox" src={trash} alt="delete-logo"/></div></div></Draggable>);
        return (


            <div className="float-container">
                
              <divclassName="container float-child">{studentNames}
              
              </div>
              
              <div className="float-child">
              <div><h4>Teacher:</h4><div></div><p>FIRSTNAME LASTNAME</p></div>
              <h3>Student Info</h3>

              <div id = "editForma">
                <form>
                  <label >First Name:</label>
                    <input type="text" name="firstName" value={this.state.firstName} onChange={this.handleFirstNameChange} />
                    <div></div>
                  <br></br>
                    <label >Last Name:</label>
                    <input type="text" name="lastName" value={this.state.lastName} onChange={this.handleLastNameChange}/>
                    
                    <button className="button button2" type="submit" onClick={() => this.editStudent(this.state.studentId)}>Edit Student</button>
                </form>

                
                </div>

              </div>
            </div>

        );
      }
    }

export default App;

Now, when I chose the student I want to edit, I edit first and last name to be "Kate" and "smith", at the end of the request process, my page goes to http://localhost:8080/?firstName=Kate&lastName=Smith, which is the part I do not understand.

Now, once it navigates there, even when I refresh the page and go back to http://localhost:8080/, it gets "stuck".

As for the errors, I am not receiving any in 95% of the cases, just once I received the error:

this is body { firstName: 'Kate', lastName: 'Smith' }
[1] MongoServerError: not primary
[1]     at MessageStream.messageHandler (/Users/milospopovic/Desktop/Code/teacher-solo/node_modules/mongodb/lib/cmap/connection.js:462:30)
[1]     at MessageStream.emit (node:events:390:28)
[1]     at processIncomingData (/Users/milospopovic/Desktop/Code/teacher-solo/node_modules/mongodb/lib/cmap/message_stream.js:108:16)
[1]     at MessageStream._write (/Users/milospopovic/Desktop/Code/teacher-solo/node_modules/mongodb/lib/cmap/message_stream.js:28:9)
[1]     at writeOrBuffer (node:internal/streams/writable:390:12)
[1]     at _write (node:internal/streams/writable:331:10)
[1]     at MessageStream.Writable.write (node:internal/streams/writable:335:10)
[1]     at TLSSocket.ondata (node:internal/streams/readable:777:22)
[1]     at TLSSocket.emit (node:events:390:28)
[1]     at addChunk (node:internal/streams/readable:324:12) {
[1]   topologyVersion: { processId: new ObjectId("6226493d3f6cbc2e7ec62cd9"), counter: 54 },
[1]   ok: 0,
[1]   code: 10107,
[1]   codeName: 'NotWritablePrimary',
[1]   '$clusterTime': {
[1]     clusterTime: new Timestamp({ t: 1647717344, i: 2 }),
[1]     signature: {
[1]       hash: new Binary(Buffer.from("c1c7efa296c48125954f75a0da484b63fd9a69de", "hex"), 0),
[1]       keyId: new Long("7030875868872310785")
[1]     }
[1]   },
[1]   operationTime: new Timestamp({ t: 1647717343, i: 1 }),
[1]   [Symbol(errorLabels)]: Set(1) { 'RetryableWriteError' }
[1] }

CodePudding user response:

You must use the foms's proprety onSubmit to pass your request handler function. Remember to receive the event parameter and run 'event.preventDefault()', to prevent the default redirect and redirect behavior.

<form onSubmit={
    onClick={(event) => {
        event?.preventDefault() 
        this.editStudent(this.state.studentId)
        }
    }}>
        <label >First Name:</label>
        <input 
            type="text" name="firstName" 
            value={this.state.firstName} 
            onChange={this.handleFirstNameChange} />
        <div></div>
        <br></br>
        <label >Last Name:</label>
        <input 
             type="text" 
             name="lastName" value={this.state.lastName} 
             onChange={this.handleLastNameChange}/>
        <button className="button button2" type="submit" >Edit Student</button>
</form>

Maybe it works too, if you only change the "type" property of button to "button" instead of "submit". I never did this way, but maybe it works.

  • Related