0

I'm not sure what I could do to make this work...So I'm calling API data (which is just a bunch of nested json objects) to create a menu. So far I have it working so that it renders the first layer of objects (first img), and when you click on each element, the next level shows up below it (second img). This works recursively, so I assume it to work for the next level down when I click on an element in "level 2", but this is not the case.

Can anyone see what I could change in my code to make this work?

class Menu extends React.Component {
  state = {
    categories: [],
    list: ""
  };


  //handle displaying list of values when clicking on button
  //search for list of values within object
  handleSearch = (obj, next, event) => {
    // console.log(event.target.name);
    Object.keys(obj).forEach(key => {
      if (typeof obj[key] === "object") {
        if (next === key) {
          //create DOM  CHILDREN
          createData(Object.keys(obj[key]), key, this.test, event);
        }
        this.handleSearch(obj[key], next);
      }
    });
  };

  componentDidMount() {
    axios.get("https://www.ifixit.com/api/2.0/categories").then(response => {
      this.setState({ categories: response.data });
    });
  }

  render() {
    return (
      <React.Fragment>
        {/* display list of things */}
        <div className="columns is-multiline">
          {Object.keys(this.state.categories).map(key => (
            <div className="column is-4">
              <div
                onClick={event =>
                  this.handleSearch(this.state.categories, key, event)
                }
              >
                {key}
              </div>
              <div name={key + "1"} />
            </div>
          ))}
        </div>
      </React.Fragment>
    );
  }
}

and here is the code for createData, which creates the next level of data and is supposed to make it so these elements can be clicked to show the next level

var index = 1;
export function createData(data, key, search, e) {
  e.stopPropagation();
  let parent = document.getElementsByName(key + "1");

  //create elements and append them
  for (let i = 0; i < data.length; i++) {
    let wrapper = document.createElement("ul");
    wrapper.innerHTML = data[i];
    wrapper.name = data[i] + index + 1;
    wrapper.addEventListener("click", search(data[i]));
    parent[0].append(wrapper);
  }
}

first level of objects second level

here's a screenshot of "categories" in the console (objects within objects within objects) categories

2
  • show us how categories looks, you should render everything from the start Commented May 10, 2019 at 17:09
  • @DennisVash I added a screenshot of what categories looks like when i do console.log Commented May 10, 2019 at 17:23

2 Answers 2

1

For simplicity we will render this nested object recursively which is structured as your categories object:

const categories = {
  level1: {
    "level1-1": {
      "level1-1-1": {
        "level1-1-1-1": {}
      }
    },
    "level1-2": {
      "level1-2-1": {}
    }
  },
  level2: {}
};

Recursion end condition will be an object without keys.

For every layer, render the keys and make a recursion step.

const makeMenuLayer = layer => {
  const layerKeys = Object.entries(layer).map(([key, value]) => (
    <>
      {key}
      {makeMenuLayer(value)}
    </>
  ));
  return <div>{layerKeys}</div>;
};

Will result:

level1
level1-1
level1-1-1
level1-1-1-1
level1-2
level1-2-1
level2

Checkout the sandbox example.

Edit o49onn9n45

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much Dennis! This really helps a lot.
1

You should try to avoid manipulating the DOM by creating/appending elements with vanilla JS while using React if possible, one of its main strengths is the virtual DOM which manages rendering for you and avoids conflicts.

Not sure how deep the objects you're rendering go, but due to the complexity of the data this would be a good case for using another component to modularize things and avoid the messiness you're dealing with now.

Assuming all the child objects are structured the same, you could create a component that renders itself recursively based on the object keys. This answer should help.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.