Free React Course
For Beginners

L2 - What is React Component

React For Beginners by Itera

Key Points

  • What is the component
  • Why to use the components
  • Component types
  • How to pass data into the component
  • How to get data from the component
  • Component lifecycle

What is the component

Component

An independent unit of code that encapsulate single, logical functionality

From React prospective component

is a function or class that accepts props (input) and returns JSX

First good candidates are

  • Buttons, inputs, links
  • Cards, grids, decorations
  • Complex stuff you want to hide from yourself

How small a component should be

It's always much easier to merge components rather than split. Feel free to make them as small as you feel comfortable

Why to use the components

Reusing

Components are very useful for re-using logic or styles. Create one component and use it across all over the application.

Example:

What is the component

...

Why to use component

VS

<AppH2>What is the component</AppH2>
...
<AppH2>Why to use component</AppH2>

Reusing gives you

  • Less mistakes
  • Speed up the coding
  • Better maintainability

Encapsulation

Components hides complexity and the realization to make you deal with them as easy as possible

Example

const handleChange = (v: number) => console.log(v);
const App = () => {
  return (
    <ComplexCounter initialValue={0} onChange={handleChange}/>
  );
};
      

Encapsulation gives you

  • Much more easier maintenance
  • Better developer experience

Readability

const App = () => {
  return (
    <>
      <AppNav />
      <WelcomeHeader />
      <Avatar />
      <Bio />
      <Contacts />
      <Footer />
    </>
  );
};

And testing

It's much more easier to test a single, small component which has one or few responsibilities that the whole App Components are great for testing which increase maintainability.

Easier tests = less bugs and fragility

Component types

Functional components

const App = () => {
  return <h1>Hello World</h1>;
};
    
const App = () => (<h1>Hello World</h1>);
        
function App() {
  return <h1>Hello world</h1>;
}
    

With TypeScript

import { FC } from 'React';

type AppLabelProps = { text: string; for: string };

const AppLabel: FC<AppLabelProps> = (props) => {
  return (
    <label htmlFor={props.for}>
      {props.text}
    </label>)
};
// usage
<AppLabel for="email" text="Your email" />

Class Based components

import { PureComponent } from 'React';

class App extends PureComponent {
  render() {
    return <h1>Hello world</h1>;
  }
}
import { Component } from 'React';

class App extends Component {
  render() {
    return <h1>Hello world</h1>;
  }
}
  

The difference between FC and ClassBased Component

  • Nature - function VS class
  • The way we access state - useState() VS this.setState()
  • LifeCycle hooks - some of them are not accessible for the FC

Another differentiation - "dumb" and "smart"

Dumb Components eg. presentational

export const AppGreetings = () => (
  <h1 className="header header1">I am a nice header</h1>
);
    

Dumb components: no state inside, made only for being nice

Smart components - contains the state, contains logic

Previously, before React 16.8 it was possible only with class based components

Class Based Smart Component

import { PureComponent } from 'react';

class BtnWithCounter extends PureComponent {
  state = { counter: 0 };
  private _increment = () => 
    this.setState({ counter: this.state.counter + 1 });
  
  render() {
    return (
      <button onClick={this._increment}>
        Clicked: {this.state.counter} times
      </button>
    );
  }
}

Typical Mistake

class BtnWithCounter extends PureComponent {

private _increment(){ 
    this.setState({ counter: this.state.counter + 1 });
}
...
    

With hooks now we can have state as well

import { useState } from "react";

const BtnWithCounter = () => {
  const [counter, setCounter] = useState(0);
  return (
      <button onClick={() => setCounter(counter+1)}>
        Clicked: {counter} times
      </button>
  );
};

What does [counter, setCounter] means?

const [counter, setCounter] = useState(0);//destruction
const array = useState(0);
const counter = array[0];
const setCounter = array[1];
    

Why should I care about this types?

Unless you don't want to work alone - you need to understand some obvious terminology

How to pass data into the component

  • From props - should be preferred
  • From context
  • Directly from the code

Using props - the most correct

        import { FC } from "react";

type H1Props = { userName: string };

const AppH1: FC<H1Props> = (props) => (
  

Hello {props.userName}

); export default () => <AppH1 userName="Hello world" />

Same way it works with class based component

import { PureComponent } from "react";

type Props = { text: string };
class AppH1 extends PureComponent<Props> {
  render() {
    return <h1>{this.props.text}</h1>;
  }
}

You can pass to props anything

type Props = {
    userName: string;             // string
    userAge: number;              //number
    isAdmin: boolean;             // boolean
    badges: string[];             // array
    contacts: { email: string };  // object
    callback: ()=> void           // function
    icon: JSX.Element;            // Even another element
};

Simpler way to pass single component

import { FC, PropsWithChildren } from "react";

type Props = PropsWithChildren<{}>;

export const AppH1: FC<Props> = (props) => {
  return <h1 className="header header1">{props.children}</h1>;
};

const App = () => <AppH1><TranslatedText text="hello"/></AppH1>

About the context we will talk a bit later

How to get data from the component

Callback - the best option to get data from the component

    import { FC } from "react";

type BtnProps = { 
  onClick: (val: string) => void 
};

const Btn: FC<BtnProps> = (props) => (
  <button onClick={() => props.onClick("hello!")} />
);

<Btn onClick={(v) => alert(v)} />
    

Common mistake:

      import { FC } from "react";
  
const Btn: FC<BtnProps> = (props) => (
  <button onClick={props.onClick("hello!")} />
);
      
  
⚠️Important: Using anonymous functions as a callback might heart the performance

Let's combine it all together

Create presentation component AppButton

type BtnProps = { text: string; onClick: () => void };

const AppBtn: FC<BtnProps> = ({ text, onClick }) => (
  <button className="btn btn-prime" type="button" onClick={onClick}>
    {text}
  </button>
);      

Create a smart component App

const App = () => {
  const [counter, setCounter] = useState(0);
  return (
    <>
      <h1>Counter: {counter} times</h1>
      <AppBtn onClick={() => setCounter(counter + 1)} text="Click me" />
    </>
  );
};

Note

  • AppBtn can be used all over the project
  • App doesn't care about the way click will be emitted

Component lifecycle

Class Based

  • Initialization
  • Render
  • ComponentDidMount
  • ShouldComponentUpdate
  • Render
  • ComponentDidUpdate
  • ComponentDidCatch
  • ComponentWillUnmount

Functional

  • -
  • function()
  • useEffect(, [])
  • -
  • function()
  • useEffect()
  • -
  • useEffect

What about others?

Other lifecycle events are either deprecated like componentWillMount either beyond this course for beginners like useLayoutEffect or getSnapshotBeforeUpdate

Most useful are

  • ComponentDidMount for one time actions like fetching the server
  • ComponentDidUpdate for side effect
  • ComponentWillUnmount for cleanup

Functional example

export default function App() {
  useEffect(() => {
    console.log("fires each and every update");
  });

  useEffect(() => {
    console.log("fires once, upon did mount");
  }, []);

  useEffect(() => {
    return () => console.log("fires on component did unmount");
  });
  return <>Test</>;
}
    

Class Based example

export default class App extends Component {
  constructor(p: {}) { super(p); }
  render(){ return <>Test</> }
  componentDidMount() {}
  shouldComponentUpdate(){ return true; }
  componentDidUpdate() {}
  componentDidCatch() {}
  componentWillUnmount() {}
}
    

The importance of knowing component lifecycle

Imagine you known nothing about the lifecycle and put fetch call inside the render. Each time your component will be re-rendered, each time you will fire request to the sever. Which will change the state, which will invoke one more re-render. Despair

Takeaway

  • Component - an independent unit of code that encapsulate single, logical functionality
  • Components might be class based or functional
  • Components divided into "smart" and "dumb"
  • Components have lifecycle you can hook into

Home task

  • Split your APP into the logical components
  • Mix Class Based and Functional approach to get more practice in both
  • Use props only to pass the data to your components

Useful links

Join me

Twitter
GitHub