【问题标题】:Best way to fetch value from database to show on React front end从数据库中获取值以显示在 React 前端的最佳方式
【发布时间】:2019-11-09 23:13:24
【问题描述】:

当用户单击按钮时,我正在尝试在我的 react 应用程序的客户端中显示使用 mongoose 存储的集合属性的值。

通过在单击时检索值并使用 setState 存储该值。

我的问题 -- 我似乎无法在单击时立即设置状态并显示新值... 在下一次点击时,显示的值是上一次点击的值。

我用于从 mongodb 获取数据的后端 node.js 代码

app.post('/api/showengagement', async (req, res) => {
const result = await Post.findOne({url: req.body.url}, "likes");
res.send(result);

})

我的前端 react.js 代码用于处理 onClick 并显示获取的数据

handleLike(url, e){
    if (e.target.innerText.toLowerCase() === "like"){
        axios.post('/api/showengagement', {url: url})
                .then(res => this.setState({
                    likeEngage: res.data.likes
                }));
        e.target.innerText = `This post has ${this.state.likeEngage} like(s)`
        axios.post('/api/incrementlikes', {url: url});
    }
    else{
        e.target.innerText = "Like";
        axios.post('/api/decrementlikes', {url: url});
    }
}

感谢您的帮助!

【问题讨论】:

    标签: javascript node.js reactjs axios


    【解决方案1】:

    您看到了错误的值,因为您在完成 axios.post 之前设置了 e.target.innerText。您可以将该代码移动到回调中以获得所需的操作顺序,如下所示:

    handleLike = (url, e) => {
        if (e.target.innerText.toLowerCase() === "like"){
            axios.post('/api/showengagement', {url: url})
            .then(res => {          
              e.target.innerText = `This post has ${res.data.likes} like(s)`
             });
            axios.post('/api/incrementlikes', {url: url});
        }
        else{
            e.target.innerText = "Like";
            axios.post('/api/decrementlikes', {url: url});
        }
    }
    

    通过这种方式,您甚至不需要将值存储在state 中。如果代码中的其他地方需要它,您仍然可以这样做。

    innerText 的设置发生在值返回之前的原因是 axios.post 是异步的,并且在操作完成之前返回并且您的函数继续下一行(将文本设置为旧值) .当post 完成并调用您的回调函数时,新值会稍后出现。

    更好:避免使用 innerText - 使用 render()

    另一种方法是让您的render() 函数负责使用state 变量将值写入适当的位置。当您调用this.setState() 时,它会导致组件再次呈现,您会看到该值出现。这是一个显示它的工作 React 类:

    import React from "react";
    
    let likes = [];
    let urls = ["url1", "url2"];
    
    class Sample extends React.Component {
      constructor(props) {
        super(props);
        this.state = { likeEngages: [] };  // initialize the array of likeEngages
      }
      // fake implementation of 'post' instead of axios.post 
      post = (url, body) => {
        if (!likes[body.id]) likes[body.id] = 1;
        if (url === "/api/showengagement") {
          return Promise.resolve({ data: { likes: likes[body.id] } });
        } else {
          likes[body.id]++; // increment Likes for given id
          return Promise.resolve();
        }
      };
    
      handleLike = (url, e) => {
        const id = e.target.id;
        this.post("/api/showengagement", { url, id }).then(res => {
          const engages = this.state.likeEngages;
          engages[id] = res.data.likes;  // set the likes count in the state
          this.setState({ likeEngages: engages });
        });
        this.post("/api/incrementlikes", { url, id });
      };
    
      showLikes = id => {
        if (this.state.likeEngages[id])
          return (
            <span>
              {" This post has " + this.state.likeEngages[id] + " like(s)"}
            </span>
          );
        return " No likes yet";
      };
    
      render() {
        return (
          <div>
            <ul>
              <li>
                <button id="id1" onClick={e => this.handleLike(urls[0], e)}>
                  Like1
                </button>
                {this.showLikes("id1")}
              </li>
              <li>
                <button id="id2" onClick={e => this.handleLike(urls[1], e)}>
                  Like2
                </button>
                {this.showLikes("id2")}
              </li>
            </ul>
          </div>
        );
      }
    }
    
    export default Sample;
    

    【讨论】:

    • 它抛出了一个错误 Cannot set property 'innerText' of null 。我猜这是因为axios.post 函数无法访问handleLike() 中的e 参数
    • 我将 handleList 更改为使用 => 语法定义。试试看 - 它可能会有所帮助
    • 如果不是,则返回使用状态,但是在使用状态时,您最好保留在render中显示值的逻辑,如第二部分所示
    • 您是否尝试将值的显示移动到您的render 函数中?流程是您在post 回调中设置状态,并在您的render 中使用它
    • 是的,我做到了...但问题是,我使用的是 list 组件,这意味着从状态数组中获取的每个列表项都有一个不同的 like 值 .. 我不能使用另一个数组来保存每个列表项的like,因为我不知道如何将 like value 链接到正确的列表项......
    【解决方案2】:

    将您的 setState 更新为以下内容;

    this.setState({...this.state, likeEngage: res.data.likes})
    

    如果这不能解决问题,您需要在 setState 之后调用 incrementLikes,如下所示

    this.setState({...this.state, likeEngage: res.data.likes}, () => incrementlikes(url))
    

    【讨论】:

    • 谢谢,但这不起作用。我也没有incrementLikes(url) 函数。仅作为发布请求端点
    • 代码不会像那样立即工作,您需要对其进行解构,以便incrementlikes() 成为一个函数。此外,解决此问题的最佳方法是按照@always-learning 的建议在渲染中使用状态。
    • 是的,我在渲染中使用了状态...但问题是,我使用的是 列表组件,这意味着每个列表项都是从状态中获取的数组,具有不同的 like 值 .. 我不能使用另一个数组来保存每个列表项的 like,因为我不知道如何链接 like 值 i> 到正确的列表项....
    猜你喜欢
    • 2021-04-01
    • 2023-03-16
    • 1970-01-01
    • 2016-12-02
    • 2018-11-07
    • 1970-01-01
    • 2021-07-17
    • 2018-05-29
    • 2010-10-07
    相关资源
    最近更新 更多