Vegeta
Vegeta

Reputation: 119

Button not being rendered

I am trying to create a new dynamic button for every title by reading the contents of the json file stored in the local directory.

JSON File

[
    {
        "page" : "Page1" ,
        "imptopics":[
            {
                "title" : "Btn1",
                "url" : "https:link/"
            },
            {
                "title" : "Btn2",
                "url" : "http:link/"
            },
            {
                "title" : "Btn3",
                "url" :"http:link"
            },
            {
                "title" : "Btn4",
                "url" : "http:link"
            }
        ]
    }
]

This is my react component, I am using fetch to read the contents of json file,

import React from 'react'
import { useState , useEffect } from 'react'
import { Button } from 'antd'


function ImportantTopics() {
    const [data,setData] = useState([]);

    const getData = () =>{
        fetch('popularlinksdata.json'
        ,{
            headers :{
            'Content-Type': 'application/json',
            'Accept' : 'application/json'
            }
        }
        )
          .then(function(response){
              return response.json();
          })
          .then(function(myJson){
              console.log(myJson)
              setData(myJson)
          });
    }
    
    useEffect(() => {
        getData()
    }, [])

    return (
        <div className="grid grid-cols-2 gap-6">
            {
                data && data.length > 0 && data.map((topic) => {
                    topic.imptopics.forEach(element => {
                        console.log(element.title);
                        <Button  className="sprtLinksButton">{element.title}</Button>      
                    })
                }) 
            }
        </div>
    )
}

export default ImportantTopics;

But the button is not being rendered, It is being displayed in the console. What can I be missing?

Upvotes: 0

Views: 55

Answers (3)

user12688644
user12688644

Reputation:

The JSON content is actually an array and we don't know how many elements there are. If you want to render all the imtopics appearing in the JSON content, you can merge the imtopics into one.

import React from 'react';
import { useState, useEffect } from 'react';
import { Button } from 'antd';


function ImportantTopics() {
  const [data,setData] = useState([]);
  const getData = () => {
    fetch('popularlinksdata.json', {
      headers :{
        'Content-Type': 'application/json',
        'Accept': 'application/json'
      }
    })
    .then(response => response.json())
    .then(function(myJson) {
      const imptopics = myJson.reduce((merged, item) => [...merged, ...item.imptopics], []);
      // we will have all the imtopics merged into `imptopics`
      setData(imptopics);
    });
  };

  useEffect(() => {
    getData()
  }, []);

  return (
    <div className="grid grid-cols-2 gap-6">
      {
        data && data.length > 0 && data.map((topic, index) => (<Button key={index} className="sprtLinksButton">{topic.title}</Button>))
      }
    </div>
  );
}

export default ImportantTopics;

Upvotes: 2

Vishnu
Vishnu

Reputation: 1701

forEach doesn't return anything whereas map returns an array. So you can either change the forEach to map or push the elements needs to be rendered to a variable and render that variable. I'd recommend the first option. Example:

import React from 'react'
import { useState , useEffect } from 'react'
import { Button } from 'antd'


function ImportantTopics() {
    const [data,setData] = useState([]);

    const getData = () =>{
        fetch('popularlinksdata.json'
        ,{
            headers :{
            'Content-Type': 'application/json',
            'Accept' : 'application/json'
            }
        }
        )
          .then(function(response){
              return response.json();
          })
          .then(function(myJson){
              console.log(myJson)
              setData(myJson)
          });
    }
    
    useEffect(() => {
        getData()
    }, [])

    return (
        <div className="grid grid-cols-2 gap-6">
            {
                data && data.length > 0 && data.map((topic) => {
                    topic.imptopics.map((element, imdex) => (
                        <Button key={index} className="sprtLinksButton">{element.title}</Button>      
                    ))
                }) 
            }
        </div>
    )
}

export default ImportantTopics;

There are two things to note here:

  1. arrow function has implicit return, but when {} is used, you should use return as stated in the other answers.
  2. when you render an element array, a unique key is required. I've given index as key in the example. If any unique identifier is available in your case, I'd recommend using that.

Upvotes: 0

JULIEN PICARD
JULIEN PICARD

Reputation: 1862

You need to return an Element or an array of Element. You a re not returning anything here

Upvotes: 0

Related Questions