简体   繁体   中英

how to dynamically render reactjs components from json data

I have some json data. 3 different objects. I would like to take the data from those objects and present it on the screen. basically each object has a name, summary and icon. so I'd like to go through all 3 of these objects and display on the screen each icon, name and summary. these objects are featured apps. they are displayed in a grid. each app has its own badge. the badge is in the AppBadgeHomePage.js file.

right now nothing is rendering. I get the h3 tag and that's it. there's a div class for "featured" but there is nothing below. it seems the this.state.feat.map is broken. or not working. or maybe it is and there's just nothing getting passed to the app badge. I call the featured apps grid in another file just fine. I'm just wondering if this is one of those cases where I'm too tired and have been staring at this for too long.

the json data looks like this. the icon and summary are in a customData object.

{
 name: appName,
 customData: {
     icon: iconURL,
     summary: summary
  }
 }

Marketplace.js

import AppBadgeHomePage from './AppBadgeHomePage';
import React, { Component } from 'react';

export default class FeaturedGrid extends React.Component {
    
    constructor(props){
        super(props);
        this.getFeaturedApps = this.getFeaturedApps.bind(this);
        let name, summary, icon;
    }
    
    state = {
        feat: []
    }

    getFeaturedApps = () => {
        fetch(`http://localhost:3001/apps/featured`)
        .then(response => response.json())
        .then(responseJson => {
            this.setState({
                feat: responseJson.map(item => ({
                    name: item.name,
                    icon: item.customData.icon,
                    summary: item.customData.summary
                }))
            })
        })
    }
    render(){
        return (
            <div>
                <h3>Featured Apps</h3>
                    <div className="featured">
                        {this.state.feat.map(featured => (
                            <AppBadgeHomePage 
                                name={featured.name}
                                icon={featured.customData.icon}
                                summary={featured.customData.summary}
                            />
                        ))}
                    </div>
            </div>
        )
    }
}

AppBadgeHomePage.js

import React, { Component } from 'react';

export default class AppBadgeHomePage extends React.Component {
    
    render(){
        return (
            <a className="featured-grid-item-badge" href="www.google.com">
                <div className="featured-grid-item">
                    <img className="featured-appIcon" src={this.props.icon} />
                        <div>
                            <p className="featuredTitle">{this.props.name}</p>
                        </div>
                        <div>
                            <p className="badgeSummary">{this.props.summary}</p>
                        </div>
                </div>
            </a>
        )
    }
}

Why are you mapping for feat ,feat supposed to be an array

Try this :-

 getFeaturedApps = () => {
    fetch(`http://localhost:3001/apps/featured`)
    .then(response => response.json())
    .then(responseJson => {
        this.setState({
            feat: responseJson
            }))
        })
    })
}

First of all, you need to console.log(this.state.feed) under render method to see if the feed array is not blank always.

If its blank then I would suggest you to call the the API in componentDidMount() method.

If its not blank then you would notice that the feed state has the object which you have already set it to your desired key value pair so there is no need to this:

<AppBadgeHomePage 
   name={featured.name}
   icon={featured.customData.icon}
   summary={featured.customData.summary}
/>

rather do this:

<AppBadgeHomePage 
   name={featured.name}
   icon={featured.icon}
   summary={featured.summary}
/>

To sum it up, if the child component is not being rendered than the array must be blank all the way. And if the child component is being rendered and the value is not showing up then the key being called is wrong.

From the react docs:

constructor

Avoid introducing any side-effects or subscriptions in the constructor. For those use cases, use componentDidMount() instead.

  1. The data fetch should be dispatched from componentDidMount lifecycle method.
  2. Don't mix using the constructor and initializing state in the class body.
  3. getFeaturedApps is an arrow function, so there is no need to bind this to it in the constructor.
  4. You should check for successful fetch in the promise chain. You should also handle promise rejections and other thrown errors from the returned promise chain.
  5. When mapping this.state.feat you incorrectly try to access what was the original nested values, but you flattened the feature element when it was mapped in the fetch response handling.

Code:

class FeaturedGrid extends React.Component {
  state = {
    feat: []
  };

  componentDidMount() {
    this.getFeaturedApps();
  }

  getFeaturedApps = () => {
    fetch(`http://localhost:3001/apps/featured`)
      .then((response) => {
        if (!response.ok) {
          throw new Error('Response not ok');
        }
        return response.json();
      })
      .then((responseJson) => {
        this.setState({
          feat: responseJson.map((item) => ({
            name: item.name,
            icon: item.customData.icon,
            summary: item.customData.summary
          }))
        });
      })
      .catch(console.error);
  };

  render() {
    return (
      <div>
        <h3>Featured Apps</h3>
        <div className="featured">
          {this.state.feat.map((featured) => (
            <AppBadgeHomePage
              name={featured.name}
              icon={featured.icon}
              summary={featured.summary}
            />
          ))}
        </div>
      </div>
    );
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM