REACT
Introduction & basics
introductie
Canvas
React.js
JavaScript library om webinterfaces te bouwen
React =
React Ecosystem
React.js
= syntax extension, JS-bestand dat lijkt om HTML
JSX is geen valid JS, browsers kunnen het niet lezen.
Het moet eerst compiled worden voor het geïnterpreteerd kan worden door de browser.
De JSX compiler zet de JSX om naar JavaScript
const h1 = <h1>Hello world</h1>;
= JS Expressions
const imgCat = <img src='images/cat.jpg' alt='cat'>;
const introduction = (
<a href="https://www.example.com">
<h1>
Hello World
</h1>
</a>
);
JSX elementen mogen maar exact 1 buiten-element hebben
const introduction = (
<h1>Hello World</h1>
<h2>Dit is niet ok</h2>
);
const introduction = (
<div>
<h1>Hello World</h1>
<h2>Dit is ok</h2>
</div>
);
const introduction = (
<>
<h1>Hello World</h1>
<h2>Dit is ook ok</h2>
</>
);
Fragments
Geen extra node in de DOM
Maak gebruik van accolades
let expr = <h1>{10 * 10}</h1>;
let introduction =
<h1>
Hello, {fullName(user)}!
</h1>
Het woord class is gereserveerd in JS, daarom maken we gebruik van className ipv class om een klasse toe te voegen aan een JSX element
<h1 class="small">Hello World</h1>
const heading = <h1 className="small">Hello World</h1>
JSX elementen moeten altijd een closing tag hebben
<img src="cat.jpg" > //-> niet ok
<img src="cat.jpg" /> //-> wel ok
een attribuut als unieke indentifier
<ul>
<li key="key1">One</li>
<li key="key2">Two</li>
<li key="key3">Three</li>
<li key="key4">Four</li>
</ul>
JSX ondersteund geen if/else
Andere opties:
if
statement outside a JSX element&&
operatorconst heading = ( <h1> { age >= drinkingAge ? 'Buy shots' : 'Buy candy' } </h1>);
const heading = (
{ age >= drinkingAge &&
<h1> Buy shots you are {age}</h1>
}
React uses Virtual DOM, which can be thought of as a blueprint of the DOM. When any changes are made to React elements, the Virtual DOM is updated. The Virtual DOM finds the differences between it and the DOM and re-renders only the elements in the DOM that changed. This makes the Virtual DOM faster and more efficient than updating the entire DOM.
Een blueprint van een huis aanpassen gaat sneller dan het effectieve huis aanpassen
React.js
Benodigheden
npx create-react-app myfirstreactapp
myfirstreactapp
├── node_modules
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ ├── serviceWorker.js
│ └── setupTests.js
├── .gitignore
├── package.json
├── package-lock.json
└── README.md
cd myfirstreactapp
npm start
Verander naar de juiste directory (folder)
Start
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React>
<App />
</React>
);
Aanmaken van een root container en renderen van een component
React.js
Herbruikbare stukjes van de interface
src/components/Button.js
import React from "react";
export default function Button() {
return (
<button>My Button</button>
);
}
src/components/Button.js
import React from "react";
export default function Button() {
return (
<button>My Button</button>
);
}
import React from "react";
import Button from "./components/Button";
function App() {
return (
<div>
<Button />
</div>
);
}
export default App;
src/App.js
Properties doorgeven
src/components/Button.js
import React from "react";
export default function Button({ txt }) {
return (
<button>{txt}</button>
);
}
import React from "react";
import Button from "./components/Button";
function App() {
return (
<div>
<Button txt="Hi Everybody"/>
</div>
);
}
export default App;
src/App.js
Componenten kunnen interactie hebben met elkaar
import React from "react";
import Button from "./components/Button";
function App() {
return (
<div>
<Button txt="Hi Everybody"/>
</div>
);
}
export default App;
src/App.js
import React from "react";
import Button from "./components/Button";
function App() {
const btnTxt = "Hi Everybody"
return (
<div>
<Button txt={btnTxt}/>
</div>
);
}
export default App;
src/App.js
import React from "react";
import TeamCard from "./components/TeamCard";
function App() {
return (
<div>
<TeamCard name="Evelien" jobFunction="CEO" />
<TeamCard name="Josh" />
</div>
);
}
export default App;
src/App.js
import React from "react";
export default function TeamCard({ name, jobFunction = "Employee" }) {
return (
<>
<h2>{name}</h2>
<p>{jobFunction}</p>
</>
);
}
src/components/TeamCard.js
const scruffy = {
src: 'linkto_catpicture.jpg',
alt: 'Scrufy goes fishing',
};
function Cats() {
return (
<div>
<h1>My Cat</h1>
<img
src={scruffy.src}
alt={scruffy.alt}
/>
</div>
);
}
Voeg nooit dubbele aanhalingstekens toe rond accolades:
const element = <img src="{user.avatarUrl}" />; //bad stuff!
Name: ES7+ React/Redux/React-Native snippets
rfc + tab
React Functional Component
General
Eenmaal je een export default ... toevoegt zal je de variabele in andere modules kunnen importeren. Met default is er maar 1 element dat je wilt exporteren, je kan de naam bij de import wijzigen
const colors = [
"#007bff",
"#f1c40f",
"#27ae60",
"#e74c3c",
"#8e44ad",
"#3498db",
"#f39c12",
];
export default colors;
import colorsData from "./colors.js";
console.log(colorsData);
Exporteren van meerdere waardes van een bepaalde module. Je moet naar de exacte naam verwijzen
export const colors = [
"#007bff",
"#f1c40f",
"#27ae60",
"#e74c3c",
"#8e44ad",
"#3498db",
"#f39c12",
];
export const getRandomColor = () => {
return colors[Math.floor(Math.random() * colors.length)];
};
import { colors, getRandomColor } from "./colors.js";
console.log(colors);
console.log(getRandomColor());
General
function SubmitButton() {
function handleClick() {
alert('Submission Successful.');
}
return
(<button onClick={handleClick}>
Submit
</button>);
}
React.js
Drie grote categorieën
Mounting
Update
Unmounting
Een component mount wanneer het voor de eerste keer rendert. Het zal de volgende drie methodes aanspreken
React.js
Hooks are functions that let us “hook into” state and lifecycle functionality in function components.
Hergebruik van stateful logica tussen componenten
Hooks roep je niet genest aan, enkel top level. Dus niet in loops, conditions of in geneste functies
Enkel in React Function Components en niet Class Components
useState geeft de huidige state van een component en zijn setter-functie. Een state kan je enkel aanpassen door zijn setter-functie
1. useState import
import React, { useState } from 'react';
2. useState
const [state, setState] = useState(initialValue);
const [name, setName] = useState('');
function setNewName(newName) {
setName(newName);
}
function Counter({ initialCount }) {
const [count, setCount] = useState(initialCount);
return (
<div>
Count: {count}
<button onClick={() => setCount(initialCount)}>Reset</button>
<button onClick={() => setCount((prevCount) => prevCount - 1)}>-</button>
<button onClick={() => setCount((prevCount) => prevCount + 1)}>+</button>
</div>
);
}
prevCount geeft de huidige state weer voor we het aanpassen
useEffect genereert een side-effect telkens er een component wordt gerenderd
2 argumenten: useEffect(callback, dependencies)
1. useEffect import
import React, { useEffect } from 'react';
2. useEffect and callback
useEffect(
() => {
// Runs side effect here
return () => {
// Do clean up here
};
},
[] // Array of dependencies
);
2b. useEffect and dependencies
[ ]
[ data ]
Run after initial render
Run after initial render and after every other render
Run after initial render and after data has changed
nothing
3. useEffect and cleanup function
optioneel wat je returned
Zal aangesproken worden voor dat de effect weer wordt aangesproken en als het component uit de DOM wordt verwijderd
useEffect(
() => {
// Runs side effect here
return () => {
// Do clean up here
};
},
[] // Array of dependencies
);
React.js
Inline CSS met de style-property
// Passing the styles as an object
const warning = {
color: 'tomato',
background: 'mistyrose'
};
<div style={warning}>Watch out, a massive dinosaur!</div>
// Passing the styles with an inline object, as a shorthand
<div style={{ color: 'tomato' }}>I am tomato-red!</div>
Gebruik Camelcase voor CSS-properties
const style = {
fontSize: '2rem', // String value with units
fontWeight: 700, // Numeric value interpreted as "700"
margin: 10, // Numirec value without unit is interpreted as pixels
};
components/box/box.css
.box {
margin: 2rem;
border: 1px solid black;
}
.box__content {
font-size: 1rem;
text-align: center;
}
import React from 'react';
import './box.css';
export default const Box = () => (
<div className="box">
<p className="box__content">
Dit is gecentreerde tekst met een zwarte rand rond!
</p>
</div>
);
components/box/Box.js
Button.module.css
.error {
background-color: tomato;
}
import styles from './Button.module.css'; // Import css modules stylesheet as styles
import './another-normal-stylesheet.css'; // Import regular stylesheet
export default const Button = () => {
return <button className={styles.error}>Error Button</button>;
}
another-normal-stylesheet.css
.error {
background-color: tomato;
}
Button.js
npm install styled-components
import styled from 'styled-components'
function App() {
return (
<div>
<h1>Styled Components</h1>
<p>Cillum culpa deserunt enim et.</p>
<button>Click ME!</button>
</div>
);
}
export default App;
src/App.js
import styled from 'styled-components'
const H1 = styled.h1`
color: red;
font-size: 4rem;
`
export default function App() {
return (
<div>
<H1>Styled Components</H1>
<p>Cillum culpa deserunt enim et.</p>
<button>Click ME!</button>
</div>
);
}
src/App.js
import styled from 'styled-components'
const DefaultButton = styled.button`
background-color: #645cfc;
border: none;
padding: 10px;
color: white;
`
export default function App() {
return (
<div>
<h1>Styled Components</h1>
<p>Cillum culpa deserunt enim et.</p>
<DefaultButton>Click ME!</DefaultButton>
</div>
);
}
src/App.js
React.js
Stap 1 : install package
import * as React from 'react';
import Avatar from '@mui/material/Avatar';
import Stack from '@mui/material/Stack';
export default function ImageAvatars() {
return (
<Stack direction="row" spacing={2}>
<Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg" />
<Avatar alt="Travis Howard" src="/static/images/avatar/2.jpg" />
<Avatar alt="Cindy Baker" src="/static/images/avatar/3.jpg" />
</Stack>
);
}
Stap 2: import component
npm install @mui/material @emotion/react @emotion/styled
Stap 1 : install package
Stap 2: init to create config-file tailwind.config.js
npm install -D tailwindcss
npx tailwindcss init
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
...
}
Stap 3 : add to index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
Stap 4 : read documentation
Uitbreiding: Flowbite
Stap 1 : install package
npm i flowbite-react
Stap 2 : add to config
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
"node_modules/flowbite-react/lib/esm/**/*.js",
],
theme: {
extend: {},
},
plugins: [require("flowbite/plugin")],
};
Uitbreiding: Flowbite
Stap 3 : use components
import React from "react";
import { Avatar } from "flowbite-react";
export default function AvatarImage() {
return (
<Avatar
img="https://mighty.tools/mockmind-api/content/human/57.jpg"
alt="avatar of Jese"
rounded
/>
);
}
React.js
Een library met navigatie componenten voor React.
npm install react-router-dom
Stap 1: include package
Routes aanmaken door JSX elementen mee te geven door gebruik te maken van `createRoutesFromElements`
import { createBrowserRouter, createRoutesFromElements, Route } from 'react-router-dom';
const router = createBrowserRouter(createRoutesFromElements(
<>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />}} />
</>
)
));
import { createBrowserRouter, createRoutesFromElements, Route } from 'react-router-dom';
const router = createBrowserRouter(createRoutesFromElements(
<Route path='/' element={ <Home/> }/>
.....
));
export default function App () {
return (
<RouterProvider router={ router } />
);
}
import { createBrowserRouter, createRoutesFromElements, Route } from 'react-router-dom';
const router = createBrowserRouter(createRoutesFromElements(
<Route path="/" element={<Root />} errorElement={<ErrorPage />}>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />}}
/>
</Route>
)
));
import React from "react";
import Navigation from "./Navigation";
import { Outlet } from "react-router-dom";
export default function Root() {
return (
<div>
<Navigation />
<main>
<Outlet />
</main>
</div>
);
}
We gebruiken geen <a>
-tag in react maar Link
en NavLink
NavLink is een speciale Link dat weet indien het "actief", "pending" of "transitioning" is. Ideaal voor navigaties
<Link to="/about">About</Link>
<NavLink to="/about">About</NavLink>
Een <Navigate>
element veranderd de huidige locatie
const UserProfile = ({ loggedIn }) => {
if (!loggedIn) {
return (
<Navigate to='/' />
)
}
import { useNavigate } from "react-router-dom";
function useLogoutTimer() {
const userIsInactive = useFakeInactiveUser();
const navigate = useNavigate();
useEffect(() => {
if (userIsInactive) {
fake.logout();
navigate("/session-timed-out");
}
}, [userIsInactive]);
}
navigate(-1)
- navigate to the previous URL in the history stack.navigate(1)
- navigate to the next URL in the history stack.navigate(-3)
- navigate 3 URLs back in the history stack.Mogelijkheid tot dynamic routes
const route = createBrowserRouter(createRoutesFromElement(
<Route path='/articles/:title' element={ <Article /> }/>
))
let { title } = useParams();
Toegang tot de value van een URL Parameter
Toegang krijgen tot de waarde van de query parameters
// Rendered when a user visits "/list?order=DESC"
export const SortedList = (numberList) => {
const [ searchParams, setSearchParams ] = useSearchParams();
const sortOrder = searchParams.get('order');
console.log(sortOrder); // Prints "DESC"
};
Search Parameters aanpassen
const [ searchParams, setSearchParams ] = useSearchParams();
// render the numberList in ascending order
<button click={ () => setSearchParams( {order: 'ASC'} ) }>
Sort
</button>
elke Route kan een loader bevatten om data te voorzien voor dat het rendert
const [ searchParams, setSearchParams ] = useSearchParams();
// render the numberList in ascending order
<button click={ () => setSearchParams( {order: 'ASC'} ) }>
Sort
</button>
React.js
React.js
export const useToggle = (initialState = false) => {
const [state, setState] = useState(initialState);
const toggle = () => { setState(state => !state) }
return [state, toggle]
}
hooks/useToggle.js
React.js
Met Context kunnen we een stukje state gecentraliseerd opslaan
om prop drilling tegen te gaan - in diep liggende structuren props doorgeven
1. Create Context
import { createContext } from 'react';
export const MyContext = createContext();
import { useContext } from 'react';
import { MyContext } from './MyContext.js'
const ChildComponent = () => {
const value = useContext(MyContext);
return <p>{value}</p>;
}
2. Use Context
3. Provide the context
import { MyContext } from '../context/MyContext.js';
const ParentComponent = () => {
return (
<MyContext.Provider value="Hello world!">
<ChildComponent />
</MyContext.Provider>
);
}
Complexere state, zeker als de verschillende elementen gerelateerd zijn aan elkaar. Anders gebruik je useState
1. Create reducer method: met state & action
const myReducer = (state, action) => {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
return state;
}
};
1. Create reducer method:
const myReducer = (state, action) => {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
return state;
}
};
2. Create Initiale state
const initialState = {
count: 0,
};
3. useReducer
function MyComponent() {
//call useReducer and pass in the reducer and an initial state
const [state, dispatch] = useReducer(myReducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>
Increment
</button>
<button onClick={() => dispatch({ type: "decrement" })}>
Decrement
</button>
</div>
);
}
3. useReducer
const [state, dispatch] = useReducer(reducer, initialState);
Onze eigen reducer-function
Initiële state
functie om de reducer functie uit te voeren
onze curren state om te gebruiken
4. dispatch: type & payload
dispatch({ type: "increment", payload: id })
React.js
Schema Models aanmaken
Project Settings > API Access > Endpoints > Yes, initialize defaults
Read-only permissions of opstellen van een token
1. Install library/dependencies
npm install @apollo/client graphql
2. configureer Apollo Client
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';
const client = new ApolloClient({
uri: '',
cache: new InMemoryCache(),
});
index.js
3. Provider toevoegen
root.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
);
index.js
Nieuw bestand + queries
import { gql } from "@apollo/client";
export const GET_TODOS = gql`
query getTodos {
todos {
description
id
isCompleted
title
}
}
`;
graphql/queries.js
Gebruik query met useQuery()
import { GET_TODOS } from "./graphql/queries";
....
const { loading, error, data } = useQuery(GET_TODOS);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error : {error.message}</p>;
return (
<div>
{data.todos.map((todo) => (
<div key={todo.id}>
<h2>{todo.title}</h2>
<p>{todo.description}</p>
</div>
))}
</div>
);
export const GET_POST_BY_SLUG = gql`
query getPostBySlug($slug: String = "") {
post(where: { slug: $slug }) {
content {
html
}
title
}
}
`;
....
const { loading, error, data } = useQuery(GET_POST_BY_SLUG, {
variables: { slug },
});
Permissions aanpassen + token aanmaken
const client = new ApolloClient({
uri: process.env.REACT_APP_HYG_API,
cache: new InMemoryCache(),
headers: {
Authorization: `Bearer ${process.env.REACT_APP_HYG_AUTH}`,
},
});
React.js
React.js
This reusable React component will manage all of your changes to the document head.
<Parent>
<Helmet>
<title>My Title</title>
<meta name="description" content="Helmet application" />
</Helmet>
<Child>
<Helmet>
<title>Nested Title</title>
<meta name="description" content="Nested component" />
</Helmet>
</Child>
</Parent>
Nested or latter components will override duplicate changes
React.js
Stateful components container
Behandeld complexe states en logica
Stateless components presentational
Enkel JSX - domme components
React.js
React.js
React.js