在刷新和状态更改时更新页面

时间:2020-06-15 19:58:08

标签: javascript reactjs

我正在尝试创建一个待办事项页面,可以在其中输入待办事项。所有待办事项将在下面呈现。我设法建立了一个表单,可以在其中键入待办事项标题并将其发送到我的数据库。我在这里遇到的一个小问题是,我需要在按下添加按钮以查看新列表后刷新页面。我认为这是因为我使用componentDidMount,并且此更新仅在页面刷新时进行。知道如何在页面刷新(componentDidUpdate)和状态更改时执行此操作吗?

前端

import React from 'react'
import './Todo.css'  
import Todoitem from '../components/Todoitem'
import axios from 'axios'
import qs from "qs"
import DefaultLayout from "../layout/Default"

class Todo extends React.Component {
    constructor() {
        super()

        this.state = {
            title:"",
            todos:[]
        }
        this.handleChange=this.handleChange.bind(this)
        this.handleSubmit=this.handleSubmit.bind(this)
    }

    componentDidMount(){
        axios({
            method: "GET",
            url: `${process.env.REACT_APP_API_BASE}/todo`,
            withCredentials: true
        })
            .then(response => {
            console.log(response)
            let todolist = response.data;
            this.setState({todos:todolist})
        })
        .catch(error => {
            console.log("You've made an error when getting the todos charles: ",error)
        })
    }

    handleChange(event){
        event.preventDefault()
        let name = event.target.name
        let value = event.target.value
        this.setState({
            [name]:value
        })
        console.log(this.state.title)
    }

    handleSubmit(event){
        event.preventDefault()
        if (!this.state.title) {
            debugger
        }  
        axios({
            method: "POST",
            url: `${process.env.REACT_APP_API_BASE}/todo`,
            data: qs.stringify({title: this.state.title}),
            headers: {"content-type": "application/x-www-form-urlencoded"},
            withCredentials: true
        })
        .then((response) => {
            console.log(response)
        })
        .catch((error) => {
            console.log(error.response)
        })
    }

    handleDelete(todoId){
        axios
        .delete(`${process.env.REACT_APP_API_BASE}/todo/${todoId}`)
        .then(response => {
            const remainingTodos = this.state.todos.filter(element => element._id !== todoId)
            this.setState({
                todos: remainingTodos
            })
        })
        .catch(err => console.log(err))
    }

    render() {
        return (
            <div>
                <DefaultLayout>
                <h1>To-do things for this app</h1>
                <h2 className="todotitle">Add your to-do here, Charles!</h2>
                <form className="todocontainer" onClick={this.handleSubmit}> 
                    <div className="inputbuttonandfield">    
                        <div className="inputcontainer">
                            <div className="captionpart">
                                <label className="captionlabel" htmlFor="title">Add to-do:</label><br></br>
                                <input className="captionform" type="text" name="title" value={this.state.title} placeholder="Type your to-do here!" onChange={(e) => this.handleChange(e)}></input>
                                <button className="shootbutton">Add!</button>
                            </div>
                        </div> 
                    </div>
                </form> 

                {
                    this.state.todos.map(element=> (
                     <div className="todosoverviewlister" key={element._id}>
                        <Todoitem id={element._id} title={element.title} />

                        <button className="tododelete" onClick={()=> this.handleDelete(element._id)}>Delete</button>
                     </div>
                    ))
                }

                </DefaultLayout>
            </div>
        )
    }
}

export default Todo

Todomodel

const mongoose = require("mongoose")
const Schema = mongoose.Schema

const todoSchema = new Schema({
    title: String
})

const Todo = mongoose.model("todos",todoSchema)

module.exports = Todo

后退

//request todos
router.get("/todo", (req,res) => {
  Todo
  .find()
  .then(response => {
    res.json(response)
  })
  .catch(error => {
    res.json(error)
  })
})

//delete todo
router.delete("/todo/:id", (req,res)=>{
  Todo
  .findByIdAndDelete(req.params.id)
  .then(response => {
    res.json(response)
  })
  .catch(error => {
    res.json(error)
  })
})

2 个答案:

答案 0 :(得分:2)

我认为问题在于提交时(在添加操作期间)您没有更新状态。在删除操作中,您还可以通过在本地删除元素来正确地使列表与服务器上的列表保持同步状态。在添加中,您应该通过将新元素添加到状态列表中来进行类似操作(或更准确地说,进行深拷贝并覆盖状态下的列表)。那应该做。

除非有多个用户在同一列表上操作,否则无需从服务器重新获取整个列表。如果是这样,您可以在提交的响应中添加get()调用。只要该操作的响应写入状态,它就会正确更新。但同样要避免这种情况,除非您需要它,否则会使您的应用变慢且响应速度变慢。

答案 1 :(得分:2)

您可以通过发送另一个GET更新状态或与数据库同步。让我将其分解为2个解决方案:

  • 只需更新状态
  • 在POST请求之后发出GET请求并更新状态

只需更新状态

// you code ...
handleSubmit(event){
  event.preventDefault()
  const newTodo = { title: this.state.title };                // extract your todo into const

  axios({
      method: "POST",
      url: `${process.env.REACT_APP_API_BASE}/todo`,
      data: qs.stringify(newTodo),                         // send todo in the POST
      headers: {"content-type": "application/x-www-form-urlencoded"},
      withCredentials: true
  })
  .then((response) => {
      console.log(response)
      this.setState(prevState => ({                        // immutably update the state
        todos: [...prevState.todos, newTodo]
      }));
  })
  .catch((error) => {
      console.log(error.response)
  })
}
// your code ...

在POST之后发送GET:

// your Todo component
class Todo extends React.Component {
  constructor() {
    super();

    this.state = {
      title: "",
      todos: [],
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  // extract method for loading TODOs (your previous componentDidMount)
  loadTodos = () => {
    axios({
      method: "GET",
      url: `${process.env.REACT_APP_API_BASE}/todo`,
      withCredentials: true,
    })
      .then((response) => {
        console.log(response);
        let todolist = response.data;
        this.setState({ todos: todolist });
      })
      .catch((error) => {
        console.log(
          "You've made an error when getting the todos charles: ",
          error
        );
      });
  }

  componentDidMount() {
    this.loadTodos();                                 // use the extracted method
  }

  handleChange(event) {
    event.preventDefault();
    let name = event.target.name;
    let value = event.target.value;
    this.setState({
      [name]: value,
    });
    console.log(this.state.title);
  }

  handleSubmit(event) {
    event.preventDefault();
    if (!this.state.title) {
      debugger;
    }
    axios({
      method: "POST",
      url: `${process.env.REACT_APP_API_BASE}/todo`,
      data: qs.stringify({ title: this.state.title }),
      headers: { "content-type": "application/x-www-form-urlencoded" },
      withCredentials: true,
    })
      .then((response) => {
        console.log(response);
        this.loadTodos();                            // use the extracted method
      })
      .catch((error) => {
        console.log(error.response);
      });
  }

  handleDelete(todoId) {
    axios
      .delete(`${process.env.REACT_APP_API_BASE}/todo/${todoId}`)
      .then((response) => {
        const remainingTodos = this.state.todos.filter(
          (element) => element._id !== todoId
        );
        this.setState({
          todos: remainingTodos,
        });
      })
      .catch((err) => console.log(err));
  }

  render() {
    return (
      <div>
        <DefaultLayout>
          <h1>To-do things for this app</h1>
          <h2 className="todotitle">Add your to-do here, Charles!</h2>
          <form className="todocontainer" onClick={this.handleSubmit}>
            <div className="inputbuttonandfield">
              <div className="inputcontainer">
                <div className="captionpart">
                  <label className="captionlabel" htmlFor="title">
                    Add to-do:
                  </label>
                  <br></br>
                  <input
                    className="captionform"
                    type="text"
                    name="title"
                    value={this.state.title}
                    placeholder="Type your to-do here!"
                    onChange={(e) => this.handleChange(e)}
                  ></input>
                  <button className="shootbutton">Add!</button>
                </div>
              </div>
            </div>
          </form>

          {this.state.todos.map((element) => (
            <div className="todosoverviewlister" key={element._id}>
              <Todoitem id={element._id} title={element.title} />

              <button
                className="tododelete"
                onClick={() => this.handleDelete(element._id)}
              >
                Delete
              </button>
            </div>
          ))}
        </DefaultLayout>
      </div>
    );
  }
}

export default Todo;