Nested Component And Composition model | ReactJS - part 6

← How to Style A React Component? - part 5

React reusable components - Learn nested components and composition pattern with elpeeda.net


I'll go over nesting components, children in JSX, prop-drilling; the composition model in this tutorial. 

As I mentioned before, the component allowed us to split our code across multiple files, so if we need one block multiple times, we will simply repeat that component rather than write that code multiple times. 

Not only would it clean up our code, but it would also make it reusable. You may consider it a nuisance while learning, but it will come in handy when you build a real-world application.

Nested Component

Nested components assist in creating UI that is more complex, but first we must understand what a nested component is. To put it simply, a parent component that renders additional components is referred to as a nested component.

React tutorial - How do you use a component inside another component in React - learn with elpeeda.net


To fully understand it in React, We will go practically. Create another component file called "Lists" and remove the following data from <MYComponent> and add it to <Lists>.  


 Lists.js

import List from './List'
const Lists = ({detail}) => {
  
  return (
    <section>
      <List 
      name={detail[0].name} 
      language={detail[0].language} 
      level={detail[0].level} />

      <List 
      name={detail[1].name} 
      language={detail[1].language} 
      level={detail[1].level} />
            
      <List 
      name={detail[2].name} 
      language={detail[2].language} 
      level={detail[2].level} />
    >/section<
  )
}
export default Lists;

To output data properly on the screen we will now import it into <MyComponent> and pass the props by adding the 'details' attribute to the Lists in JSX and It will render relative to that parent.

const MyComponent = (props) => {
    const className = props.active ? 'active' : 'default'

    const course = [
        {
            name: 'Sandmus',
            language: 'JavaScript',
            level: 'Beginner'
        },
        {
            name: 'Simba',
            language: 'HTML/CSS',
            level: 'Medium'
        },
        {
            name: 'Jenny',
            language: 'JavaScript',
            level: 'Advance'
        }
    ]
    return (
        <div className='container'>
            <h5>{props.title}</h5>
            <p>{props.text}</p>
            <button className={`${className} shape`}>Add List</button>
            <Lists detail={course} />
        <;/div>
    )
}
export default MyComponent

Numerous layouts and designs demand the use of nested components. As an illustration, you could create a nesting component like <Lists> inside of a parent component with a background fill.

React Composition

When we talk about reusability, we think about components, so what role does composition play? It is, after all, shareability, I suppose. This means that two parts can share the parts that make them up. 

We define composition as the arrangement of the parts of something to get the desired output.

By using composition, we can get rid of duplicate code, which stops us from writing similar components or similar code that contains duplicate code. Two components can share functionality thanks to composition.

Let's modify some code before moving on to make it appear as though we are building something along the way.

Create a List.css file and paste the code into this file.

List.css

.list {
  border: 2px solid #333;
  border-radius: 12px;
  max-width: 100%;
  margin: 1rem;
  padding: 0.5rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

Add some styling to our <MyComponent>.

StylesComponent.css

.container {
  max-width: 500px;
  width: 100%;
  margin: auto;
  display: flex;
  flex-direction: column;
  padding: 1rem;
  background-color: aliceblue;
  border: 2px solid #333;
  border-radius: 12px;
  font-family: sans-serif;
  text-align: center;
}
.container p {
  padding: 0;
  margin: 0;
  font-size: 1.4rem;
}

react application - learn with elpeeda.net


Let's examine the component, and similarities between codes.

React reusable components

If we look at the outcome, both of our containers have the same fancy border, which indicates that we used some styling repetition, which means <MyComponent> and <Lists> share the same styling. The common styles between them can be extracted and placed in a separate component.

Let's create another file in a component folder named 'FancyBorder', we will handle it in the same manner as a regular component, it returns the element with className 'fancyBorder"

FancyBorder.js

const FancyBorder = () => {

  return <div className="fancy-border"></div>
}
export default FancyBorder


Now create a FancyBorder.css file. We'll now remove the duplication styling from other CSS files and add it to FancyBorder.css using a class selector and import it at the top of the <FancyBorder> component. 

FancyBorder.css

.fancy-border {
  border: 2px solid #333;
  border-radius: 12px;
}

This <FancyBorder> component will now be reused throughout our application. We can simply replace 'div' with our newly created component and it will automatically apply predetermined styles.

import FancyBorder from './FancyBorder'
const MyComponent = () => {
  return (
  <FancyBorder className='container'>
     <h5>{props.title}</h5>
     <p>{props.text}</p>
     <button className={`${className} shape`}>Add List</button>
     <Lists detail={course} />
  </FancyBorder>
 )
}

But what makes a composition different from a regular component? You cannot, however, use custom components as wrappers around other types of content in the same manner.

For using this kind of wrapper which contains both an opening and closing tag, we will use a special prop: props.children. Any data passed within those tags is passed into the <FancyBorder> component as a children prop.

Because we applied the className prop to the custom component, it will not immediately support CSS classes, so if you look at the browser, you will notice that styles are missing. We will add some code inside the <FancyBorder> in order to set a class name.

const FancyBorder = (props) => {

  const classes = "fancy-border " + props.className;

  return <div className={classes}>{props.children}</div>
}
export default FancyBorder

As a result, any class names we receive from outside sources are now added to the string. Pass the expression you created earlier at the className attribute. With this, the className prop will be added to the string.

The outcome is the same as it was earlier. Now, instead of using the div, we can wrap <FancyBorder> around <List> as well.

List.js

constList = () => {
  return (
    <FancyBorder className="list">
      <h3>{name}</h3>
      <span>{language} : {level}</span>
    </FancyBorder>
  )
}

Props Drilling

If I move this whole data from <MyComponent> to the App file and make this variable globally accessible across the component. 

function App() {
  const course = [
        {
            name: 'Sandmus',
            language: 'JavaScript',
            level: 'Beginner'
        },
        {
            name: 'Simba',
            language: 'HTML/CSS',
            level: 'Medium'
        },
        {
            name: 'Jenny',
            language: 'JavaScript',
            level: 'Advance'
        }
    ]
}

Because data is transferred in a single direction, we need to pass data through several nested child components for rendering, even MyComponent does not need it but is forced to take it in. We called it props drilling.

return <MyComponent detail={course}  title={name} text='Enjoy your journey' active={true} />

React tutorial - what is prop drilling and a better way of solving - learn with elpeeda.net


As you can see, the array object that holds the information is only available at the root component and has to be drilled down through several nested components in order to render the list of information. You can handle it if it passes through 3 or 4 levels deep down, but it becomes hell if it goes deeper.

The simplest way to solve this problem is to use component composition; instead of passing the 'detail' attribute through components, we will compose the component at the root file.

Components can be passed as children or  props  just like any other type of data thanks to component composition. We're going to nest the JSX inside the App component to pass the children there instead of nesting the <Lists> component inside <Mycomponent> so that it won't know the children in advance.


import MyComponent from './component/MyComponent'
import Lists from './component/Lists'

function App() {

  const course = [
        {
            name: 'Sandmus',
            language: 'JavaScript',
            level: 'Beginner'
        },
        {
            name: 'Simba',
            language: 'HTML/CSS',
            level: 'Medium'
        },
        {
            name: 'Jenny',
            language: 'JavaScript',
            level: 'Advance'
        }
    ]
  return (
    <MyComponent title={name} text='Enjoy your journey' active={true}>
      <Lists detail={course} />
    </MyComponent>
  )
}
export default App


Then, pass the props directly from the App component while including special children prop to pass the children component directly into <MyComponent>.

const MyComponent = (props) => {
  const className = props.active ? 'active' : 'default'
  return (
    <FancyBorder className='container'>
      <h5>{props.title}</h5>
      <p>{props.text}</p>
	  <button className={`${className} shape`}>Add List</button>
      {props.children}
    </FancyBorder>
  )
}

Conclusion

Here In this tutorial, I go over how to extract components and how to use component composition to prevent code duplication and solve the props drilling problem as well.  Go ahead and look at the React series if you are a little confused by all the codes written here.

There are no limitations on how you can build UI functionality using the component and composition pattern because it gives you all the freedom you need to explicitly and safely alter a component's appearance and behavior.


0 Comments:

Post a Comment