An independent unit of code that encapsulate single, logical functionality
is a function or class that accepts props (input) and returns JSX
It's always much easier to merge components rather than split. Feel free to make them as small as you feel comfortable
Components are very useful for re-using logic or styles. Create one component and use it across all over the application.
What is the component
...
Why to use component
<AppH2>What is the component</AppH2>
...
<AppH2>Why to use component</AppH2>
Components hides complexity and the realization to make you deal with them as easy as possible
const handleChange = (v: number) => console.log(v);
const App = () => {
return (
<ComplexCounter initialValue={0} onChange={handleChange}/>
);
};
const App = () => {
return (
<>
<AppNav />
<WelcomeHeader />
<Avatar />
<Bio />
<Contacts />
<Footer />
</>
);
};
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
const App = () => {
return <h1>Hello World</h1>;
};
const App = () => (<h1>Hello World</h1>);
function App() {
return <h1>Hello world</h1>;
}
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" />
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>;
}
}
export const AppGreetings = () => (
<h1 className="header header1">I am a nice header</h1>
);
Dumb components: no state inside, made only for being nice
Previously, before React 16.8 it was possible only with class based components
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>
);
}
}
class BtnWithCounter extends PureComponent {
private _increment(){
this.setState({ counter: this.state.counter + 1 });
}
...
import { useState } from "react";
const BtnWithCounter = () => {
const [counter, setCounter] = useState(0);
return (
<button onClick={() => setCounter(counter+1)}>
Clicked: {counter} times
</button>
);
};
const [counter, setCounter] = useState(0);//destruction
const array = useState(0);
const counter = array[0];
const setCounter = array[1];
Unless you don't want to work alone - you need to understand some obvious terminology
import { FC } from "react";
type H1Props = { userName: string };
const AppH1: FC<H1Props> = (props) => (
Hello {props.userName}
);
export default () => <AppH1 userName="Hello world" />
import { PureComponent } from "react";
type Props = { text: string };
class AppH1 extends PureComponent<Props> {
render() {
return <h1>{this.props.text}</h1>;
}
}
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
};
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>
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)} />
import { FC } from "react";
const Btn: FC<BtnProps> = (props) => (
<button onClick={props.onClick("hello!")} />
);
type BtnProps = { text: string; onClick: () => void };
const AppBtn: FC<BtnProps> = ({ text, onClick }) => (
<button className="btn btn-prime" type="button" onClick={onClick}>
{text}
</button>
);
const App = () => {
const [counter, setCounter] = useState(0);
return (
<>
<h1>Counter: {counter} times</h1>
<AppBtn onClick={() => setCounter(counter + 1)} text="Click me" />
</>
);
};
Other lifecycle events are either deprecated like componentWillMount either beyond this course for beginners like useLayoutEffect or getSnapshotBeforeUpdate
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</>;
}
export default class App extends Component {
constructor(p: {}) { super(p); }
render(){ return <>Test</> }
componentDidMount() {}
shouldComponentUpdate(){ return true; }
componentDidUpdate() {}
componentDidCatch() {}
componentWillUnmount() {}
}
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