Suppose you like to travel and have collected a large photo gallery. The photos are stored in a tree folder structure, where locations are structured according to the geography and administrative division:

Tree strcuture

The actual photos of particular places are stored in the corresponding leafs of the tree. Different branches of the tree may have different height. You want to show these photos in your portfolio website that is made on React. Each photo should have a title and description. Also, the gallery should be easily extendable with new locations and photos.


To show this gallery, we need two React libraries: react-tabs and pure-react-carousel or their equivalents. The tabs library provides a tree structure for the gallery locations, while the carousel shows the photos of a particular place.

Let’s take a look at a simple tabs example:

For every tab, the tab title is a <Tab> element of the <TabList>, and the tab content is placed into a <TabPanel>.

To add an extra level of tabs, one needs to insert a whole <Tabs> block into the appropriate <TabPanel>. Clearly, such construct becomes very cumbersome and hard to extend if the gallery becomes sufficiently deep. So we need to automatically inject JSX code into the <TabPanel> elements and automatically pass the appropriate titles to the <Tab> elements.

 React carousel works as follows.

The <CarouselProvider> is supplied with props of the ratio of slide width, height, and the number of slides. <Slider> wraps a list of individual <Slide> elements.

To show our photos, every photo of a particular location is placed as a <src> link to an individual <Slide>. Apparently, we need to automatically construct and pass to the carousel the path to every photo, the photo’s title, and description.

Let’s see how to solve these problems.


First, let’s pack our data to the following data structure:

The pattern is clear. For the tree nodes:

For the leaves:

It is easy to parse and generate JSX code for this data structure in a top-down recursive manner. Later in the Explanation section, we will see why. The parser and code generator is:

Here, isLeaf(arr,property) method (lines 1-4) checks if the node is a leaf. The arr argument is an array of objects. If the objects have a key named property, then the parser reached a leaf. In this case, we check for the ‘screen’ key.

The method giveJSXForLeaf(arr,pathStack(lines 5-8) generates the JSX code for a leaf; this code is a <Place> component with a carousel. The <Place> component receives two props. The first one is arr – an array of  objects with titles, file names, and descriptions. The second one is an array of strings pathStack: every string is a folder of the path to the photo files. The folders are joined (line 7) to form a path to the files.

Next, the method giveGalleryJSX(arr,pathStack) (lines 14-34) generates the JSX code for a node; the method recursively calls itself. The method emits a <Tabs> block (lines 15-32). The first argument is arr – an array of objects, either of a node or a leaf. The second argument pathStack is an array of strings, where every string is a folder of the path to the photo files – the same as in the giveJSXForLeaf method.

The giveGalleryJSX(arr,pathStack calls itself recursively at  line 25. Before the call, a new folder name is pushed to the array pathStack and popped from the array ones the recursive call returns. So, a pathStack is formed up and, after being joined, provided to the <Place> component as a prop.

In the <Place> component the two props are used to render a carousel:

Here the this.props.list is an array of leaf objects, each with a title, file name, and description.  this.props.dirName is a joined pathStack array.

As a result, we get this:

Travel gallery

Let’s see why this code works.


The gallery data structure can be parsed by the following grammar:

 Here Arr, List, and Obj are non-terminals. Key (area name string) and Cnt (leaf array) are terminals:

It is easy to see that this is a LL(1) grammar. Indeed, we can distinguish between the  Obj -> {Key:Arr} and  Obj -> {Key:Cnt} productions if we use just the single non-recursive method isLeaf(arr,property).  This check is made at the start of the giveGalleryJSX, so we don’t go deeper into the recursion. This is basically the same as checking for a first right-side terminal in a classical LL(1) grammar.

According to the compiler theory, LL(1) grammar can be parsed with a top-down recursive parser. Also, the compiler theory says, that we need a production function for every production rule. The rules 1 and 2 can be covered by a single JS array method…),  rule 3 is covered by the giveGalleryJSX, while rule 4 is covered by giveJSXForLeaf.

This analysis demonstrates that our code should work and we don’t miss anything.


In this post, we saw a simple top-down recursive algorithm to emit JSX code to build a deeply nested photo gallery with  react-tabs and pure-react-carousel libraries

Source link

Write A Comment