【问题标题】:Updating a page at refresh AND change of state在刷新和状态更改时更新页面
【发布时间】:2020-06-16 15:27:58
【问题描述】:

我正在尝试构建一个待办事项页面,我可以在其中在我的输入字段中输入待办事项。所有待办事项将在下面呈现。我设法构建了一个表单,我可以在其中输入待办事项标题并将其发送到我的数据库。我在这里遇到的一个小问题是我需要在按下添加按钮后刷新页面才能查看新列表。我认为这是因为我使用 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)
  })
})

【问题讨论】:

  • 我要尝试的第一件事是通过检查网络调试器来缩小范围。查看是否有多个请求正在发出。如果只有一个,它是否包含正确的参数?如果是这样,您的问题很可能是后端。否则,我们有更多信息可以使用
  • @BrianThompson:谢谢伙计,找到问题了!我已经更新了我的问题!介意再看看吗?

标签: javascript reactjs


【解决方案1】:

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

  • 只需更新状态
  • 在 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;

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2019-11-30
      • 1970-01-01
      • 1970-01-01
      • 2017-03-06
      • 2021-03-20
      • 1970-01-01
      • 1970-01-01
      • 2019-04-05
      • 1970-01-01
      相关资源
      最近更新 更多