Is using react hooks the proper way to dynamically add menu items from parsed json?

Viewed 30

I am new to React/JavaScript but feel like I am learning decently, so bear with me.

I have a React web app site that loads a JSON file and displays the data into groupings like so. enter image description here If it matches a specific file name, it labels it "Full Configuration", else it just displays the file name on the menu item.

After the JSON file is parsed, a div with unique ID is displayed for each grouping. I keep an array of all the div IDs.

What I would like to do, is append a menu item in the menu to view a single div of the "Full Configuration" file because this view has around 30ish groups so if a user wants to see a group that's located at the very bottom, they have to scroll all the way down.

Use case: Lets say the user only wants to see the GPS Lever Arms, there would be a menu item for "GPS Lever Arms" they could click. The menu item would change the display property of all divs to "none" except for that one. So the user would then see something like this. enter image description here

I have done some looking the past few days and it seems like the useEffect is the correct way to go about this but I have not seen it implemented in my desired way.

This is my current code that receives a json object data and creates the div per group and then displays each item inside the group.

import React, {useState} from 'react'
import ConfigParam from './ConfigParam'

export default function Grouping({data}){
    const [jsonData, setJsonData] = useState(data)

    // Array of arrays To hold the grouping results.
    var groupResults = {};
    var divIDs = [];

    for(var obj in data)
    {   
        if(data[obj].hasOwnProperty('meta') === false)
        {
            console.log(`no meta field in ${data[obj]}`);
            return <></>
        }
        else if(data[obj].meta === "")
        {
            console.log(`${data[obj]} meta field is empty`);
            return <></>
        }
        else
        {
            // check if the group property is missing - create it as empty
            if(data[obj].meta.hasOwnProperty('group') == false)
            {
                data[obj].meta.group = ""
            }

            if(!groupResults.hasOwnProperty(data[obj].meta.group))
            {
                groupResults[data[obj].meta.group] = [];
            }
            // take the name of the key and add it as a property inside the object
            data[obj].name = obj;
            // push the object onto the json
            groupResults[data[obj].meta.group].push(data[obj]);
        }
    }

    const editValue = ({name,data}) =>
    {
        var temp = jsonData;
        temp[name].value = data;
        //console.log(data)
        setJsonData(temp)
    }

    // Get the keys of the groupResults (Group names)
    const test = Object.keys(groupResults);

    return(
        test.map((member,index) =>{
            // get the keys within the current group (items)
            const subItems = Object.keys(groupResults[member]);

            // create a div id per group
            let div_id = "group-" + test[index];
            divIDs.push(div_id);
            console.log("new divID:", div_id);

            // todo - append button for each div to view each individual div. 

            return(
                <div id={div_id} style={{display:"flex", border: "1px black solid", marginBottom: "10px"}}>
                    <div style={{flex:4, margin: "10px"}}>
                        <div style={{margin: "10px"}}>
                            <h4><b>{test[index]}</b></h4>
                        </div>
                        <div style={{margin: "30px"}}>
                            {subItems.map((sub, index2)=>{
                                return(
                                    <ConfigParam
                                        editValue={editValue}
                                        key={index2}
                                        name={groupResults[member][sub].name}
                                        type={groupResults[member][sub].meta.type}
                                        value={groupResults[member][sub].value}
                                        description={groupResults[member][sub].meta.description}
                                        meta={groupResults[member][sub].meta} />
                                )
                            })}
                        </div>
                    </div>
                </div>
            )
        })
    )
}

for context, the JSON looks like this:

{
  "GPS Lever Arm X (ft)": {
    "value": 1.78,
    "meta": {
      "group": "GPS Lever Arms",
      "description": "GPS <--> IMU",
      "type": "number",
      "readOnly": false,
      "min": -1.7976931348623157e+308,
      "max": 1.7976931348623157e+308
    }
  },
  "GPS Lever Arm Y (ft)": {
    "value": 0,
    "meta": {
      "group": "GPS Lever Arms",
      "description": "GPS <--> IMU",
      "type": "number",
      "readOnly": false,
      "min": -1.7976931348623157e+308,
      "max": 1.7976931348623157e+308
    }
  },
  "GPS Lever Arm Z (ft)": {
    "value": 0,
    "meta": {
      "group": "GPS Lever Arms",
      "description": "GPS <--> IMU",
      "type": "number",
      "readOnly": false,
      "min": -1.7976931348623157e+308,
      "max": 1.7976931348623157e+308
    }
  }
}

In the event someone would like to see the menu code, here - Side note: the "grouping" file is called from the ConfigFile. - I can provide that code if needed.

import React from 'react'
import { Tab, Row, Col, Nav} from 'react-bootstrap'
import FunctionPanel from './FunctionPanel'
import VariablePanel from './VariablePanel'
import ConfigFile from './ConfigFile'

export default function MainViewColumns({groups}) {

    const member = groups[1];
    const files = member.files;
    const funcs = member.functions;
    const vars = member.variables;

    var defaultKey="controls"
    var menuItems = [];
    var viewItems = [];

    if(files)
    {   
        for(var x = 0; x < files.length; x++)
        {
            // Get the file name info
            const fullFileName = files[x].split('/').pop();
            const fileInfo = fullFileName.split(".");
            const fileExtension = fullFileName.split(".").pop();
            const filename = fileInfo[0];

            // create the menu item based on filename
            if(fullFileName === "atacnavMicroConfig.json")
            {
                defaultKey=filename;
    
                var menuItem = 
                    <Nav.Item key={filename}>
                        <Nav.Link eventKey={filename}>Full Configuration</Nav.Link>
                    </Nav.Item>
            }
            else
            {
                menuItem = 
                    <Nav.Item key={filename}>
                        <Nav.Link eventKey={filename}>{filename}</Nav.Link>
                    </Nav.Item>
            }

            // create the view item
            var viewItem = 
                <Tab.Pane key={filename} eventKey={filename} >
                    <ConfigFile file={files[x]}/>
                </Tab.Pane>

            // append menu item and view item to their respective lists. 
            menuItems.push(menuItem);
            viewItems.push(viewItem);
        }
    }

    return (
        <Tab.Container defaultActiveKey={member.name}>
            <Tab.Container defaultActiveKey={defaultKey}>
            <Row>
                <Col sm={2}>
                    <div id="navColumn">
                        <Nav variant="pills" className="flex-column">
                            <Nav.Item id="mainMenuItem">Main Menu</Nav.Item>
                            <Nav.Item key="controls">
                                <Nav.Link eventKey="controls">Controls</Nav.Link>
                            </Nav.Item>
                            {menuItems.map((item, index) => {
                                return(menuItems[index]);
                            })}
                        </Nav>
                    </div>
                </Col>
                <Col sm={9}>
                    <Tab.Content>
                        <Tab.Pane key="controls" eventKey="controls" >
                            <div style={{display: "flex", justifyContent:"space-between"}}>
                                <div style={{flex: 8, marginTop: "10px"}} className="d-flex flex-col justify-content-center">
                                    <FunctionPanel functions={funcs}/>
                                    <VariablePanel variables={vars}/>
                                </div>
                            </div>  
                        </Tab.Pane>
                        {viewItems.map((item, index) => {
                            return(viewItems[index]);
                        })}
                    </Tab.Content>
                </Col>
            </Row>
        </Tab.Container>
        </Tab.Container>
    )
}

Is useEffect the proper way to accomplish this ? if so, how would I go about implementing it? Thanks in advance.

0 Answers
Related