Getting Started with React

Building Components


Creating a component

const Message = () => {
    return <h1>Hello World</h1>;
}
export default Message;

Rendering a list

const Component = () => {
    const items = ['a', 'b', 'c'];
    return (
        <ul>
            {items.map((item)) => (
                <li key={item}> item </li>
            ))}
        </ul>
    );
};

Conditional Rendering

{items.length === 0 ? 'a' : 'b'}
{items.length === 0 && 'a'}

Handling Events

<button onClick={() => console.log('clicked')}></button>;

Defining State

const [name, setName] = useState('');

Props

interface Props {
    name: string;
}

const Component = ({ name }: Props) => {
    return <p>{name} </p>
};

Passing Children

interface Props {
    children: ReactNode
}

const Component = ({ children }: Props) => {
    return <div>{children}</div>
};

Styling Components

Vanilla CSS

.list-group { 
  list-style: none;
  padding: 0;
}
import './ListGroup.css';

function ListenGroup() {
    return <ul className="list-group"></ul>;
}

CSS Modules

import styles from './ListGroup.module.css';

function ListGroup() {
    return <ul className={styles.listGroup}></ul>
}

CSS-in-JS

import styled from 'styled-components';

const List = styled.ul`
    list-style: none;
`;

function ListGroup() {
    return <List></List>;
}

Managing Component State

Updating Objects

const [drink, setDrink] = useState({
    title: 'Americano',
    price: 5
});

setDrink({ ...drink, price: 2});

Updating Nested Objects

const [customer, setCustomer] = useState({
    name: 'John',
    address: {
        city: 'San Francisco',
        zipCode: 94111
    }
});

setCustomer({
    ...customer,
    address: {...customer.address, zipCode:94112}
})

Updating Arrays

const [tags, setTags] = useState(['a', 'b']);

// Adding
setTags([...tags, 'c']);

// Removing
setTags(tags.filter(tag=> tag !== 'a'));

// Updating
setTags(tags.map(tag => tag === 'a' ? 'A' : tag));

Updating Array of Objects

const [bugs, setBugs] = useState([
    {id: 1, title: 'Bug 1', fixed: false},
    {id: 2, title: 'Bug 2', fixed: false},
]);

setBugs(bugs.map(bug =>
            bug.id === 1 ? {...bug, fixed: true} : bug));

Updating with Immer

import produce from 'immer';

setBugs(produce(draft => {
    const bug = draft.find(bug => bug.id === 1);
    if (bug) bug.fixed = true;
}));

Building Forms

Handling Form Submission

const App = () => {
    const handleSubmit = (event: FormEvent) => {
        event.preventDefault();
        console.log('Submitted');
    };

    return (
        <form onSubmit={handleSubmit}>
        </form>
    );
};

Accessing Input fields using the ref hook

const App = () => {
    const nameRef = useRef<HTMLInputElement>(null);

    const handleSubmit = (event: FormEvent) => {
        event.preventDefault();

        if (nameRef.current)
            console.log(nameRef.current.value);
    };

    return (
        <form onSubmit={handleSubmit}>
            <input ref={nameRef} type="text" />
        </form>
    );
};

Managing form state using the state hook

const App = () => {
    const [name, setName] = useState('');

    return (
        <form>
        <input
            type="text"
            value={name}  
            onChange={(event) => setName(event.target.value)}
        />
        </form>
    );
};

Managing form state using react hook form

import { FieldValues, useForm } from 'react-hook-form';

const App = () => {
    const { register, handleSubmit } = useForm();

    const onSubmit = (data: FieldValues) => {
        console.log('Submitting the form', data);
    }

    return (
        <form onSubmit={handleSubmit(onSubmit)}>
        <input {...register('name')} type="text" />
        </form>
    );
};

Validation using HTML5 Attributes

const App = () => {
    const {
        register,
        handleSubmit,
        formState:{errors},
    } = useForm<FormData>();

    const onSubmit = (data: FieldValues) => {
        console.log('Submitting the form', data);
    };

    return (
        <form onSubmit={handleSubmit(onSubmit)}>
        <input {...register('name', {required: true})} type="text" />
        {errors.name?.type === 'required' && <p> Name is required. </p>}
        </form>
    );
};

Disabling the Submit Button

const App = () => {
    const {
        formState: {isValid},
    } = useForm<FormData>();

    return (
        <form>
            <button disabled={!isValid}>Submit</button>
        </form>
    );
};

Connecting to the Backend

Using the Effect Hook

function App() {
    useEffect(() => {
    document.title = 'App';
    }, []);
}   

Fetching Data with Axios

    const [users, setUsers] = useState<User[]>([]);
    useEffect(() => {    
    axios.get<User[]>('http://...')
        .then((res) => setUsers(res.data));
    }, []);

Handling Errors

const [error, setError] = useState('');

useEffect(() => {
    axios.get<User[]>('http://...')
    .then((res) => setUsers(res.data))
    .catch(err => setError(err.message));
}, []);

Cancelling an HTTP request

useEffect(() => {
    const controller = new AbortController();

    axios.get<User[]>('http://...', {signal: controller.signal})
    .then((res) => setUsers(res.data) )
    .catch(err => {
        if (err instanceof CanceledError) return;
        setError(err.message)
    });

    return () => controller.abort()
}, []);

Deleting, creating and updatingData

axios.delete('http://...')
axios.post('http://...', newUser)
axios.put('http://...', updatedUser)