【问题标题】:Mapping over JavaScript object fetched from Express server in React在 React 中映射从 Express 服务器获取的 JavaScript 对象
【发布时间】:2018-11-05 01:00:17
【问题描述】:

我在一个对象内部有多个阵列,用于不同类型的微量营养素(维生素、矿物质、抗氧化剂、氨基酸和欧米茄)。我希望每个人都作为<option> 在他们自己的下拉菜单中传递,显示他们自己的类型(例如维生素:维生素 B2、B6、B5 等)

我的控制台显示数据已经成功获取:

{vitamins: Array(6), minerals: Array(2), aminoacids: Array(1), antioxidants: Array(2), omegas: Array(1)}

但是当我到达 Vitamins.js 时,我正在尝试渲染选项,它显示“TypeError:vitamins.map is not a function”。

这是来自我的 Express 服务器的 res.json:

 router.get('/', function(req, res, next) {
 res.json({vitamins: [
  {
    name: "Vitamin B2"
  },
  {
    name: "Vitamin B6"
  }, 
  {
    name: "Vitamin B5"
  }
],
 minerals: [
  {
    name: "Calcium"
  },
 {
  name: "Zinc"
  }
 ] 
});
});

这里是为 Home.js 中的 res.json 声明状态的地方。 (我知道“用户”现在没有任何语义意义,我会改变它。只是想先弄清楚为什么它不起作用。)

constructor(props) {
  super(props);
  this.state = {users: []};
 }

 componentDidMount() {
   fetch('/users')
      .then(res => res.json())
      .then(users => this.setState({ users }));
 }

 render() {
   return (
      <MenuItems users={this.state.users} />
  )
}

这是 Menuitems.js,比 Home.js 低一级,我在其中调用 handleChange 函数,因此当用户单击新的微(维生素 B2 -> B6)时,新的微(B6)变成新的选择的选项。

 constructor(props) {
  super(props);
   this.state = {
    value: '',
  };

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

handleChange(e) {
  const { value } = e.target;
   this.setState({
      value: value
   });
 }

 render() {
  return (
    <ul className="menuitems">
      <li>
        <Vitamins data={this.props.users} />
      </li>
      <li>
         <Minerals data={this.props.users} />
       </li>
    </ul>
  )
}

这是 Vitamins.js(我也有 Minerals.js、AminoAcids.js 等),我试图在我的 res.json 对象中映射“vitamins”数组,并将每个名称拉入其中的选择下拉菜单。

  renderData() {
    const vitamins = this.props.data;
    console.log("the data", vitamins);
    return vitamins.map((micro, index) => {
     return (
       <option value={micro.value} key={index}>{micro.name}</option>
     )
   })
 }

  render() {
   return (
    <form>
      <select value={this.props.value} onChange={this.handleChange}>
        <option value="" selected>--Vitamins--</option>
        {this.renderData()}
      </select>
    </form>
  )
 }

renderData()中的console.log一开始什么都不会显示,但是在componentDidMount()之后它会显示这个TWICE

 the data {vitamins: Array(6), minerals: Array(2), aminoacids: Array(1), antioxidants: Array(2), omegas: Array(1)}

编辑

我接受了一些我得到的建议,并尝试应用它。

这个有效,我在每个子组件(维生素、矿物质等)内部声明了状态

 state = {users: []};

 componentDidMount() {
   fetch('/users')
    .then(res => res.json())
    .then(users => {
      this.setState({
        users: users.vitamins
      });
    })
  }

 renderData() {
   const vitamins = this.state.users;
   return vitamins.map((micro, index) => {
   return (
      <option value={micro.value} key={index}>{micro.name}</option>
    )
  })
}

但是,我不想一直在每个组件中获取。我尝试在父菜单项中声明状态,并按照建议在数据道具中传递 {this.state.users.vitamins}。

(MenuItems.js)

state = {users: []};

componentDidMount() {
  fetch('/users')
    .then(res => res.json())
    .then(users => {
     this.setState({
       users
     });
   })
 }

render() {
  return (
    <ul className="menuitems">
      <li>
        <Vitamins data={this.state.users.vitamins} />
      </li>
    </ul>
 )
}

(Vitamins.js)

 renderData() {
   const vitamins = this.props.data;
   return vitamins.map((micro, index) => {
     return (
       <option value={micro.value} key={index}>{micro.name}</option>
     )
   })
 }

但是,当我这样做时,我得到“TypeError: Cannot read property 'map' of undefined”。

如果我执行“const { Vitamins} = this.props.data”,我会收到“TypeError: Cannot read property 'vitamins' of undefined”。

那么我如何在父级获取,并将我需要的唯一数组传递给 data= ?

【问题讨论】:

  • 试试const { vitamins } = this.props.data 或:&lt;Vitamins data={this.props.users.vitamins} /&gt; + this.state = { users: {} };
  • 看来@riwu 是正确的。传递给Vitamins.js 的数据是维生素数组的父分支
  • 这是很多代码,其中大部分应该是完全不相关的:什么是您的维生素组件的道具和状态?因为这是唯一重要的部分:如果它得到一个普通对象,那么.map() 失败的原因是 100% 显而易见的。在该维生素渲染函数中执行console.log(this.props),查看您实际放入的内容,然后返回。
  • @Mike'Pomax'Kamermans 如果我在这里拆分用户 &lt;Vitamins data={this.state.users.vitamins} /&gt; ,我会从 Vitamins.js 中的渲染函数返回 console.log 中的“未定义”。如果我这样做 &lt;Vitamins data={this.state.users} /&gt;,我会在 console.log {vitamins: Array(6), minerals: Array(2), aminoacids: Array(1), antioxidants: Array(2), omegas: Array(1)} 中取回整个用户对象。
  • 所以,大幅减少它。在你构建维生素之前做一个this.state.users的console.log:复制那个字符串,扔掉你所有的东西,做一个class App extends React.Component { render() { let userstate = JSON.parse("...that string..."); return &lt;Vitamins data={userstate}/&gt;; } },看看会发生什么。这就是建议通常形成minimal reproducible example 的原因:您显示的代码几乎都不需要实际测试您的Vitamin 类正在做什么。如果表现良好,我们重复练习,提高一个组件(将数据捕获为 JSON,直接提供)。

标签: javascript reactjs express dictionary typeerror


【解决方案1】:

您当前仅获取用户。在 Vitamins.js 中,您尝试从 this.props.data 中获取数据,这将为您提供正在处理数组的信息,如控制台日志中所示。您需要先“拆分”数据,然后才能获取它。

this.setState({ users: users.vitamins)} 

例如(我不知道你的生态系统,所以无论你试图获取什么都需要在 setState 事件中关联,否则你只是在没有数据定义的情况下传递数据)。

正如评论部分已经发布的那样,您也可以在将数据传递给组件时尝试对其进行拆分:

    <Vitamins data={this.props.users.vitamins}

基本相同,你获取用户并获取维生素数据。每当你想映射一个数组时,你必须“打开”它。

这是一个基本的例子,你通常会怎么做:

  .then(response => response.json())
  .then(data => data.users.your-data-you-want-to-fetch.map((x) => {

    this.setState({
      vitamin: x.name,
      id: x.id,
      })

}))

data.vitamin / data.id 然后可以访问您的道具数据。

您好!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-30
    • 2018-02-10
    • 1970-01-01
    • 1970-01-01
    • 2019-04-10
    • 1970-01-01
    • 2019-03-10
    相关资源
    最近更新 更多