Javascript Can';使用解析服务器返回的数据更新状态后,无法让React组件重新呈现

Javascript Can';使用解析服务器返回的数据更新状态后,无法让React组件重新呈现,javascript,reactjs,parse-server,Javascript,Reactjs,Parse Server,我无法使用状态中的数据渲染组件。我从解析服务器中提取数据,然后用这些数据更新状态。但是,使用数据的组件(在下面的代码中)是在数据可用之前进行渲染的 我尝试了这里描述的方法: 但我无法让组件识别正在更新然后重新呈现的状态 有什么想法吗?代码如下所示。还附上一个屏幕截图,显示成功的控制台日志和状态中存在的数据 (需要注意的是,我是一个新手,所以很多代码可能都不是最优的。) 从“React”导入React; 从“Parse”导入Parse; 从“/MenuItem”导入菜单项; 类MenuItems

我无法使用状态中的数据渲染组件。我从解析服务器中提取数据,然后用这些数据更新状态。但是,使用数据的组件(
在下面的代码中)是在数据可用之前进行渲染的

我尝试了这里描述的方法:

但我无法让组件识别正在更新然后重新呈现的状态

有什么想法吗?代码如下所示。还附上一个屏幕截图,显示成功的控制台日志和状态中存在的数据

(需要注意的是,我是一个新手,所以很多代码可能都不是最优的。)

从“React”导入React;
从“Parse”导入Parse;
从“/MenuItem”导入菜单项;
类MenuItems扩展了React.Component{
构造函数(){
超级();
this.loadMenuItems=this.loadMenuItems.bind(this);
此.state={
菜单项:{},
顺序:{}
};
}
loadMenuItems(){
/*0a.是否获取状态的副本*/
const menuItems={…this.state.menuItems};
/*0.获取用户*/
//TODO:从道具上得到这个
var user=Parse.user.current();
/*1.获取此用户的菜单项*/
var MenuItemTest=Parse.Object.extend('MenuItemTest');
var query=newparse.query(MenuItemTest);
query.equalTo(“用户”,用户);
查询.查找({
成功:函数(返回的菜单项){
log(“成功检索”+returnedMenuItems.length+“菜单项”);
对于(var i=0;i)
}
)
}
}
导出默认菜单项;

更新代码以与注释线程一致

import React from "react";
import Parse from 'parse';

import MenuItem from './MenuItem';

class MenuItems extends React.Component {
  constructor() {
    super();

    this.loadMenuItems = this.loadMenuItems.bind(this);
  }

  loadMenuItems() {
    const menuItems = {};

    /* 0. Get User */
    var user = Parse.User.current();

    /* 1. Get Menu Items for this user */
    var MenuItemTest = Parse.Object.extend('MenuItemTest');
    var query = new Parse.Query(MenuItemTest);

    query.equalTo('user', user);
    query.find({
      success: function(returnedMenuItems) {
        console.log("Successfully retrieved " + returnedMenuItems.length + " menu items.");

        for (var i = 0; i < returnedMenuItems.length; i++) {
          var object = returnedMenuItems[i];

          const menuItem = {
            name: object.get('name'),
            price: object.get('price'),
            label: object.get('label'),
            shorthand: object.get('shorthand'),
            description: object.get('description')
          }

          menuItems[`menu-item-${object.id}`] = menuItem;
        }
      },
      error: function(error) {
        console.log("Error: " + error.code + " " + error.message);
      }
    });

    this.setState({ menuItems });
  }

  componentWillReceiveProps(nextProps) {
    console.log('I ran');
    console.log(nextProps);
    this.loadMenuItems();
  }

  componentWillMount() {
    this.loadMenuItems();
  }

  render() {
    // Handle case where the response is not here yet
    if (!this.state.menuItems) {
      console.log('No state');
      return <div>Loading...</div>;
    }

    // Gives you the opportunity to handle the case where the ajax request
    // completed but the result array is empty
    if (this.state.menuItems.length === 0) {
      console.log('Zero items');
      return <div>No menu items yet</div>;
    }

    if (this.state.menuItems) {
      return (
        <div className="menu-items">
          { console.log(this.state.menuItems) }
          { console.log(Object.keys(this.state.menuItems)) }
        </div>
      )
    }
  }
}

export default MenuItems;
从“React”导入React;
从“Parse”导入Parse;
从“/MenuItem”导入菜单项;
类MenuItems扩展了React.Component{
构造函数(){
超级();
this.loadMenuItems=this.loadMenuItems.bind(this);
}
loadMenuItems(){
常量menuItems={};
/*0.获取用户*/
var user=Parse.user.current();
/*1.获取此用户的菜单项*/
var MenuItemTest=Parse.Object.extend('MenuItemTest');
var query=newparse.query(MenuItemTest);
query.equalTo(“用户”,用户);
查询.查找({
成功:函数(返回的菜单项){
log(“成功检索”+returnedMenuItems.length+“菜单项”);
对于(var i=0;i
据我所知,从你在这里得到的信息

if (!this.state.response) {
  return <div>Loading...</div>;
}

if (this.state.response.length === 0) {
  return <div>No menu items yet</div>;
}

而您的
构造函数
根本没有将
菜单项
设置为状态(因此加载会首先显示)。

我找到了解决方案。虽然在试图解决我的问题时,我移动了一些代码来设置父组件的状态,并将其作为道具传递给MenuItems。但它为什么不起作用仍然是一样的

它与
loadMenuItems()
有关:

我相信这些组件从未更新过,因为尽管状态是通过
menuItems[
菜单项-${object.id}
]=menuItem设置的
loop
this.setState()
从未被再次调用,这就是触发组件刷新的原因。我本可以离开这里,但我想这就是发生的事情

我在下面发布了更新的代码以供将来参考

父组件

import React from "react";
import Parse from 'parse';

import MenuItems from './MenuItems';


class ManageMenu extends React.Component {
  constructor() {
    super();

    this.loadMenuItems = this.loadMenuItems.bind(this);
  }

  loadMenuItems() {
    const menuItems = {};

    /* 0. Get User */
    var user = Parse.User.current();

    /* 1. Get Menu Items for this user */
    var MenuItemTest = Parse.Object.extend('MenuItemTest');
    var query = new Parse.Query(MenuItemTest);

    query.equalTo('user', user);
    query.find({
      success: function(returnedMenuItems) {
        console.log("Successfully retrieved " + returnedMenuItems.length + " menu items.");

        for (var i = 0; i < returnedMenuItems.length; i++) {
          var object = returnedMenuItems[i];

          const menuItem = {
            name: object.get('name'),
            price: object.get('price'),
            label: object.get('label'),
            shorthand: object.get('shorthand'),
            description: object.get('description')
          }

          menuItems[`menu-item-${object.id}`] = menuItem;
        }

        this.setState({ menuItems });
      }.bind(this),
      error: function(error) {
        console.log("Error: " + error.code + " " + error.message);
      }
    });
  }

  componentWillMount() {
    this.loadMenuItems();
  }

  render() {
    // Handle case where the response is not here yet
    // console.log(this.state);
    if (!this.state) {
      console.log('No state');
      // Note that you can return false it you want nothing to be put in the dom
      // This is also your chance to render a spinner or something...
      return <div>Loading...</div>;
    }

    if (this.state.menuItems) {
      return (
        <div className="manage-menu">
          <div className="mt3 border-top">
            <h3 className="mt1 bold s2">Menu Items</h3>

            <div className="mt1">
              <MenuItems menuItems={this.state.menuItems} />
            </div>
          </div>
        </div>
      )
    }
  }
}

export default ManageMenu;
import React from "react";

import MenuItem from './MenuItem';

class MenuItems extends React.Component {
  render() {
    // Same as: const menuItems = this.props.menuItems;
    const { menuItems } = this.props;

    // No menu items yet
    if (menuItems.length === 0) {
      console.log('Zero items');
      return <div>No menu items yet</div>;
    }

    if (menuItems) {
      return (
        <div className="menu-items">
          {
            Object
              .keys(menuItems)
              .map(key => <MenuItem key={key} details={menuItems[key]} />)
          }
        </div>
      )
    }
  }
}

export default MenuItems;
从“React”导入React;
从“Parse”导入Parse;
从“/MenuItems”导入菜单项;
类ManageMenu扩展了React.Component{
构造函数(){
超级();
this.loadMenuItems=this.loadMenuIt
loadMenuItems() {
  const menuItems = {};

  /* 0. Get User */
  var user = Parse.User.current();

  /* 1. Get Menu Items for this user */
  var MenuItemTest = Parse.Object.extend('MenuItemTest');
  var query = new Parse.Query(MenuItemTest);

  query.equalTo('user', user);
  query.find({
    success: function(returnedMenuItems) {
      console.log("Successfully retrieved " + returnedMenuItems.length + " menu items.");

      for (var i = 0; i < returnedMenuItems.length; i++) {
        var object = returnedMenuItems[i];

        const menuItem = {
          name: object.get('name'),
          price: object.get('price'),
          label: object.get('label'),
          shorthand: object.get('shorthand'),
          description: object.get('description')
        }

        menuItems[`menu-item-${object.id}`] = menuItem;
      }
    },
    error: function(error) {
      console.log("Error: " + error.code + " " + error.message);
    }
  });

  this.setState({ menuItems });
}
success: function(returnedMenuItems) {
  ...
}.bind(this),
import React from "react";
import Parse from 'parse';

import MenuItems from './MenuItems';


class ManageMenu extends React.Component {
  constructor() {
    super();

    this.loadMenuItems = this.loadMenuItems.bind(this);
  }

  loadMenuItems() {
    const menuItems = {};

    /* 0. Get User */
    var user = Parse.User.current();

    /* 1. Get Menu Items for this user */
    var MenuItemTest = Parse.Object.extend('MenuItemTest');
    var query = new Parse.Query(MenuItemTest);

    query.equalTo('user', user);
    query.find({
      success: function(returnedMenuItems) {
        console.log("Successfully retrieved " + returnedMenuItems.length + " menu items.");

        for (var i = 0; i < returnedMenuItems.length; i++) {
          var object = returnedMenuItems[i];

          const menuItem = {
            name: object.get('name'),
            price: object.get('price'),
            label: object.get('label'),
            shorthand: object.get('shorthand'),
            description: object.get('description')
          }

          menuItems[`menu-item-${object.id}`] = menuItem;
        }

        this.setState({ menuItems });
      }.bind(this),
      error: function(error) {
        console.log("Error: " + error.code + " " + error.message);
      }
    });
  }

  componentWillMount() {
    this.loadMenuItems();
  }

  render() {
    // Handle case where the response is not here yet
    // console.log(this.state);
    if (!this.state) {
      console.log('No state');
      // Note that you can return false it you want nothing to be put in the dom
      // This is also your chance to render a spinner or something...
      return <div>Loading...</div>;
    }

    if (this.state.menuItems) {
      return (
        <div className="manage-menu">
          <div className="mt3 border-top">
            <h3 className="mt1 bold s2">Menu Items</h3>

            <div className="mt1">
              <MenuItems menuItems={this.state.menuItems} />
            </div>
          </div>
        </div>
      )
    }
  }
}

export default ManageMenu;
import React from "react";

import MenuItem from './MenuItem';

class MenuItems extends React.Component {
  render() {
    // Same as: const menuItems = this.props.menuItems;
    const { menuItems } = this.props;

    // No menu items yet
    if (menuItems.length === 0) {
      console.log('Zero items');
      return <div>No menu items yet</div>;
    }

    if (menuItems) {
      return (
        <div className="menu-items">
          {
            Object
              .keys(menuItems)
              .map(key => <MenuItem key={key} details={menuItems[key]} />)
          }
        </div>
      )
    }
  }
}

export default MenuItems;