Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Building A React Folder Tree Component
Anurag Hazra
Anurag Hazra

Posted on • Originally published atanuraghazra.github.io

     

Building A React Folder Tree Component

Photo byJohann Siemens on Unsplash
This post was originally published onmy personal site

Hey folks! I hope you are doing fine in this pandemic situation, Today we will be creating a Folder Tree Component in
Reactjs from scratch.

Designing the API

Before creating any type of component in reactjs you should 1st design how the API would look like and then write the
necessary code to make it work.

Our Folder Tree Component will have two APIs

  • Declarative
  • Imperative

At first we will tackle the Declarative API which is really simple to create,

and in the second section we will do the Imperative API with recursive components.

Declarative API

The declarative API would look something like this :-

importTreefrom'./Tree';constApp=()=>{return(<div><Tree><Tree.Foldername="src"><Tree.Foldername="Components"><Tree.Filename="Modal.js"/><Tree.Filename="Modal.css"/></Tree.Folder><Tree.Filename="index.js"/><Tree.Filename="index.html"/></Tree.Folder><Tree.Filename="package.json"/></Tree></div>);};
Enter fullscreen modeExit fullscreen mode

As you can see we will have total of three components to work with

  • <Tree /> (the root)
  • <Tree.Folder /> (it will be collapsible)
  • <Tree.File />

Imperative API

Declarative APIs are simple & easier for users to structure the Tree, but in real world scenarios we will have a JSON
Object representing the Folder Tree and we need to render that with the Imperative API.

importTreefrom'./Tree';conststructure=[{type:"folder",name:"src",childrens:[{type:"folder",name:"Components",childrens:[{type:"file",name:"Modal.js"},{type:"file",name:"Modal.css"}]},{type:"file",name:"index.js"},{type:"file",name:"index.html"}]},{type:"file",name:"package.json"}];constApp=()=>{return(<div><Treedata={structure}/></div>);};
Enter fullscreen modeExit fullscreen mode

As you can see we have a JSON representation of the same tree we have in our declarative API.

Its an Array of Objects and each object has three properties

  • name
  • type (defines if its a Folder or File)
  • childrens (array of nested Files & Folders)

And we just passed thisstructure to our component which will handle the rendering, we will cover the
Imperative API later in the post but let us first finish our Declarative API


The Tree Component

Lets first install styled-components for styling our Components.

npminstallstyled-components
Enter fullscreen modeExit fullscreen mode

Our Tree component will be very simple it will only have some basic styling, it is so simple i don't even have to
explain it.

constStyledTree=styled.div`  line-height: 1.5;`;constTree=({children})=>{return<StyledTree>{children}</StyledTree>;};
Enter fullscreen modeExit fullscreen mode

The File Component

In our File component we will also have a File Icon with some basic styling.

Lets installreact-icons and import our File Icon

npminstallreact-icons
Enter fullscreen modeExit fullscreen mode
import{AiOutlineFile}from'react-icons/ai';constStyledFile=styled.div`  padding-left: 20px;  display: flex;  align-items: center;  span {    margin-left: 5px;  }`;constFile=({name})=>{return(<StyledFile><AiOutlineFile/><span>{name}</span></StyledFile>);};
Enter fullscreen modeExit fullscreen mode

We have a 20px padding left to push the Component to the right a little bit, and display flex properties to align the
icon & span correctly.

That's fine but that generic file icon does not look good, does it? lets change that.

We will make a map of extension icons and depending on the file extension we will give the file appropriate icon.

import{DiJavascript1,DiCss3Full,DiHtml5,DiReact}from'react-icons/di';constFILE_ICONS={js:<DiJavascript1/>,css:<DiCss3Full/>,html:<DiHtml5/>,jsx:<DiReact/>,};exportdefaultFILE_ICONS;
Enter fullscreen modeExit fullscreen mode

And in the File component we will extract the extension from the name of the file and use that to render the icon

importFILE_ICONSfrom'./FileIcons';constFile=({name})=>{// get the extensionletext=name.split('.')[1];return(<StyledFile>{/* render the extension or fallback to generic file icon  */}{FILE_ICONS[ext]||<AiOutlineFile/>}<span>{name}</span></StyledFile>);};
Enter fullscreen modeExit fullscreen mode

It would look something like this.

Hooray our File component is done, let's move on to Folder component

File Icons

The Folder Component

In the Folder component we will have

  • folder title
  • collapsible component
  • Nested childrens of File/Folder components

Initially our Folder component is very simple, just the title and childrens.

btw if you don't know what thatchildren prop is then here's some resources

A quick intro to React’s props.children

A deep dive into children in React

import{AiOutlineFolder}from'react-icons/ai';constStyledFolder=styled.div`  padding-left: 20px;  .folder--label {    display: flex;    align-items: center;    span {      margin-left: 5px;    }  }`;constFolder=({name,children})=>{return(<StyledFolder><divclassName="folder--label"><AiOutlineFolder/><span>{name}</span></div><div>{children}</div></StyledFolder>);};
Enter fullscreen modeExit fullscreen mode

And thats it, thats all we need for our Folder component but we also wanted the folders to be collapsible so lets add
that next.

To add the collapse feature we will add a Styled component and also add local state to keep track of
isOpen state of our component.

constStyledFolder=styled.div`  padding-left: 20px;  .folder--label {    display: flex;    align-items: center;    span {      margin-left: 5px;    }  }`;constCollapsible=styled.div`  /* set the height depending on isOpen prop */  height:${p=>(p.isOpen?'auto':'0')};  /* hide the excess content */  overflow: hidden;`;constFolder=({name,children})=>{const[isOpen,setIsOpen]=useState(false);consthandleToggle=e=>{e.preventDefault();setIsOpen(!isOpen);};return(<StyledFolder><divclassName="folder--label"onClick={handleToggle}><AiOutlineFolder/><span>{name}</span></div><CollapsibleisOpen={isOpen}>{children}</Collapsible></StyledFolder>);};
Enter fullscreen modeExit fullscreen mode

There we go! Our Folder Component is done, Yey!

Finalizing Tree Component

As you've noticed in our Declerative API design, we have & components we can just assign
the File & Folder component to our Tree's static methods.

constTree=({children})=>{return<StyledTree>{children}</StyledTree>;};Tree.File=File;Tree.Folder=Folder;////////// DONE! Lets try it outimportTreefrom'./Tree';constApp=()=>{return(<div><Tree><Tree.Foldername="src"><Tree.Foldername="Components"><Tree.Filename="Modal.js"/><Tree.Filename="Modal.css"/></Tree.Folder><Tree.Filename="index.js"/><Tree.Filename="index.html"/></Tree.Folder><Tree.Filename="package.json"/></Tree></div>);};
Enter fullscreen modeExit fullscreen mode

If we run the code now we will have a working React Folder Tree Component! Congrats 🎉🎉

Declerative Demo


Imperative API

OKAY! we are done with the Declerative API now lets work on the Imperative API.

To create the Imperative API we need recursion!

If you are not familiar with recursion then check out some resources

A Quick Intro to Recursion in Javascript

Intro to Recursion in JS

In our component we accept thedata props and added anisImperative flag.

If we have the data prop and not the children that means the user is using the imperative api, and depending on that
variable we will be rendering the tree.

constTree=({data,children})=>{constisImperative=data&&!children;return<StyledTree>{isImperative?<TreeRecursivedata={data}/>:children}</StyledTree>;};
Enter fullscreen modeExit fullscreen mode

As you've noticed we also added a new component called<TreeRecursive /> which will recursively look through the JSON
structure and render those nested files/folders, Lets implement it.

constTreeRecursive=({data})=>{// loop through the datareturndata.map(item=>{// if its a file render <File />if(item.type==='file'){return<Filename={item.name}/>;}// if its a folder render <Folder />if(item.type==='folder'){return(<Foldername={item.name}>{/* Call the <TreeRecursive /> component with the current item.childrens */}<TreeRecursivedata={item.childrens}/></Folder>);}});};
Enter fullscreen modeExit fullscreen mode

Believe it or not, we are DONE! 🎉🎉 Run the code and see the magic!

Imperative Demo

Phew! That was amazing isn't it? if you made it this far, give yourself a tap on the shoulder because you just built a React Folder Tree Component!

Now for those who are looking for some more fun try to implement these features on your own :-

  • File/Folder Rename Support
  • File/Folder Creation Support
  • File/Folder Deletion Support
  • Save folder structure to localStorage Support

Foot notes

Thanks for reading the post, i hope you learned something and enjoyed it.

Stay safe, stay home!

Bye have a nice day!

Top comments(4)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
ibrahimshamma99 profile image
Ibrahim Shamma
Senior Software Engineer.I explain in words and code
  • Email
  • Location
    Amman, Jordan
  • Education
    Bachelor's in Engineering
  • Work
    Principal Engineer at Wiley
  • Joined

Very informative big like

CollapseExpand
 
anuraghazra profile image
Anurag Hazra
TypeScript Lover | Canvas, Web Interactivity, Web Physics Simulations, all kind of fun stuff. #CreativeCoder
  • Location
    Kolkata, West Bengal, India
  • Joined

Thank you, I'm glad you liked it. 🤗

CollapseExpand
 
Sloan, the sloth mascot
Comment deleted
CollapseExpand
 
anuraghazra profile image
Anurag Hazra
TypeScript Lover | Canvas, Web Interactivity, Web Physics Simulations, all kind of fun stuff. #CreativeCoder
  • Location
    Kolkata, West Bengal, India
  • Joined

Here, you can check out my example. It has full CRUD functionality.github.com/anuraghazra/react-folde...

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

TypeScript Lover | Canvas, Web Interactivity, Web Physics Simulations, all kind of fun stuff. #CreativeCoder
  • Location
    Kolkata, West Bengal, India
  • Joined

More fromAnurag Hazra

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp