DEV Community

Cover image for Fibonacci grid in React
Mohamed Eltohamy
Mohamed Eltohamy

Posted on

Fibonacci grid in React

Leonardo Fibonacci Color and Seashell with fibonacci sequence overlay

Goal

I want to create a Fibonacci grid pattern component in React that can the user can use and add elements to in any orientation.

Fibonacci View

React Component ⚛️

I started by creating a React Component called /code FibonacciGrid, and then added a couple of states.

  • Orientation is an enum that is either horizontal or vertical.
  • nBoxes for specifying the number of boxes/elements in the grid (It should be a multiple of 3)
  • elementResolution which holds the width and height of the grid specified by the user.

Component basic code structure

Grid vs Flex Layouts

Grid layout was my initial choice when I got started with this as it’s called FibonacciGrid after all and a grid looks like it’ll be the obvious choice right? … well wrong because for the design that I made, I only needed to worry about 3 elements (Probably could’ve been done easily by grid but I already did something like it with flex and I love ❤️ flex. So flex is a go; here’s the orientation that I’m aiming for:

Grid vs Flex Layouts desired view

I’m going to nest this layout in itself as you can see here:

Recursive Fibonacci view

You can see how it keeps nesting a new FibView, yeah I’m calling that now. Getting back to what's at hand, if the user sets the number of views/boxes to more than 3 then we’ll have to nest another view and repeat the process.

Design

Initial design

I made this

Output

Orientation Wars

Making the view have one behavior is simple enough, but now I need to make it dynamic.

I set up a lot of variables and this function changes the variables on orientation change….

And it worked, for the horizontal view, but not for the Vertical (as expected 🤪).

Here’s how it looked:

How the thing looks

and that's even after I applied a little bit of React Wizardry.

Orientation

if so then add it to the bottom of the flex row direction, ah yeah I did that too, now I change the flex-direction depending on the orientation.

Need to fix the vertical orientation issue

OMG!!! So I was adding the 1 view to the same flex that contains the other two views, so I ended up with the 3 views with a 37% height and that was the issue.

Reverse/Flip Orientations

Vertical reverse and horizontal reverse,

The end result should be like the one on the figure on the left, after changing a few things I set up the view to change the size to a fixed width and height based on its orientation.

For some reason, I got the following figures on the right, not the same but close. Now starts the game of trial and error.

HorizontalReverse

That was an easy one, I just needed to add one line to the condition that adds the large view to the end.

{(orientation === OrientationEnum.vertical ||
        orientation === OrientationEnum.horizontalReverse) && (
        <div
Enter fullscreen mode Exit fullscreen mode

onto the next one…

VerticalReverse

Now

Orientation Expansion

So as I was figuring out what to do I noticed that I missed a couple of orientations 4 to be exact. I was contemplating whether to implement them now or not as they’ll add an extra level of complexity, knowing me I just had to do it. This btw was a side project of a side project soooooo… let’s get into it.

I went and added the extra orientations and worked out a nifty new way to figure it all out.

Flip (the nifty way)

Flip variable

Now it’s getting complicated, but don’t worry I think I figured a way to simplify things.
I added a new variable flip which will just vertically flip all of the original 4 orientations, you can ask me why don’t I make flip-horizontal and flip-vertical, and to that, I say shhhh, not now but that is the future plan. (Something for another day).

I leave this here as there is something more important that I need to do.

Important Change

As of now most of the views are working well, I thought there should be some style added to them.

I went and downloaded a couple of beautiful images from Unsplash from these amazing artists, check their work in the links below.

Photos by Freguesia de Estrela on Unsplash

Photo by Milad Fakurian on Unsplash

Photo by Daniel J. SchwarzHire on

Photo by NEOM on Unsplash

Photo by Marek Piwnicki on Unsplash

OK, let’s address the elephant in the room (🦣 me) not you 🐘 yeah you, seriously though we need to now add children to the FibView. I’m now faced with a choice either to implement adding children to the view which is the whole point of this or add the images in the fibview itself, hmmmm.. Well as you know by now I usually take the harder route and give up midway, but that’s what what we’re gonna do right now.

So as I never did this before I jumped into React’s docs and I think it’s gonna be something like this

<FibView> 
    <img src="1.png"></img>
    <img src="2.png"></img>
    <img src="3.png"></img>
    <img src="4.png"></img>
    <img src="5.png"></img>
</FibView>
Enter fullscreen mode Exit fullscreen mode

Then in the view we’ll get the children just like what we do with ContextProviders, so something like this

SomeContextProvider(props: PropsWithChildren) {
...
    {props.children}
...
}
Enter fullscreen mode Exit fullscreen mode

And after a little digging, it is actually the way, you gotta love modular systems.

I added the children to my view like so

export default function FibonacciView({
  _orientation, children
}: PropsWithChildren<FibonacciViewProps>)
Enter fullscreen mode Exit fullscreen mode

However, now I have an issue, I need to add the children to different parts of the view, then I need to use an array of children which thankfully react got us covered on that by using 'Children.toArray(children)` .

After that, I styled the images to fill the view they’re assigned to, and then onto the assigning children to their views, then recursion which I’m trying not to think about right now. 🙆‍♂️

Views with images

The above are the 4 main orientations, I got distracted by this and didn’t do the flip. I should also have a gap setup for the view and restrict the number of children based on the total view height, but these are problems for another day and hopefully 🙏 I’ll be adding them as the days go by.

Back to Flip or BackFlip

I’m sorry 🥲 

Flip horizontal

Horizontal view and flip goal

Flip horizontal Reverse

I had to fix the Horizontal reverse as it was actually flip in the original view. To be honest, the code is getting more complicated, but my concern is not the complexity, it’s the readability of it and for that, I’m going to create a new /(Link to section)structure to further modularize the views.

Horizontal view and reverseflip goal

Horizontal view and reverseflip with images

Flip Vertical

Flip vertical

Now I’m getting the hang of it, Vertical flip works like a charm.

Flip vertical with images

Flex is acting up

I noticed a weird behavior

Flip Vertical Reverse

Flip vertical reverse

Flip vertical reverse with images

I’m so glad that everything is coming to fruition, yet I still don’t like the way it’s coded, I need to figure out a way to make it more simple to understand and use.

Aside

I’m thinking of designating different parts of the view as zones and then making different views then assigning them to the appropriate zone, I still don’t know. Please let me know your thoughts

Weird Typescript issue


{((orientation === OrientationEnum.horizontal && flip) ||
orientation === OrientationEnum.horizontal ||

OMGGGG

I just realized that I need to write the component in Javascript.

DarthVader noooo

Putting it outThere

I asked around to see how to create an npm react component for everyone to use and luckily I got a great answer from one pf the communities about where to look, and it was Vite.

After some research and checking the reviews I found that the Vite solution might have some issues with SSR (Server Side Rendering) and embedding CSS on the server like in NextJs, now I needed a faster more efficient way.

Using Tsup

Onto the Recursion

Recursive View

I figured I had to finish the recursion before I bundle it.

I’m currently trying to figure out a way that will fix the sizing as I want to dynamically set the size of the fibView and then pass a % size recursively for the views

Refactoring...

I had to refactor a couple of states within the fibView:


const [orientation, setOrientation] = useState<OrientationEnum>(_orientation);

And now I’m using a prop to set it from the parent to be able to dynamically change it.


const [elementResolution, setElementResolution] = useState<ViewResolution>(
getViewResolution(orientation, _viewResolution)
);

This also was another change for the same reason as it’ll help in the recursive step to be able to dynamically change the size and orientation of the view. Maybe I’ll revert to the original, but these states didn’t make sense as I just set them up and didn’t change them after that.


export type FibonacciViewProps = {
orientation: OrientationEnum;
_flip?: boolean;
_changeOrientation?: () => void
_viewResolution: ViewResolution;
};

This is the updated view properties… for now.

Hotfix for height

Height ap

Back to the recursion

I’ll check if we have more than 3 views I’ll have to create a child FibView recursively.
So for example If I add 8 views like so


<FibView>
<img src="1.png"></img>
<img src="2.png"></img>
<img src="3.png"></img>
<img src="4.png"></img>
<img src="5.png"></img>
<img src="6.png"></img>
<img src="7.png"></img>
<img src="8.png"></img>
</FibView>

2 should be displayed on the biggest views and then the remaining 6 images should be passed to the next FibView that's inside the smallest view which will display 2 images and have another FibView with the rest and so on.

Now that I’m thinking about it I don’t know if this is the best way to do it

HMMMMMMMMMM

HMMMMMMM

Now that I have gotten myself into this rabbit hole, I need to figure out an algorithm to calculate the next fibView in the recursion. I’ll take the horizontal view as a test case

Horizontal Flips

Take a step back (Working out the sizes of the views)

Apparently, a parent’s height needs to be determined in order for the child to use percentages, so now I’ll refactor the code in a way to retrieve the actual height of an element and cascade the effect for all of the children.

After a lot of refactoring, I managed to make it work somehow.
But now I have a better idea, instead of supplying the width and height ///

Finally finished recursion (I think)

Demo View

End Result

Top comments (0)