Intro to React
React is a frontend JavaScript library. When building large websites, code can quickly become too large and complex, leading to bugs and maintenance becoming impossible. React avoids this by using components.
This guide hopefully gives a better understanding of why and how we use react with our Card component.
What is a Card?
A card is a reusable UI component that is a container for displaying data. The card itself does not fetch data, but displays what is fed into it.
Parameters
- title: Heading at the top of the card. Is optional.
- children: The actual content that is displayed inside the card.
Files
- frontend/src/components/Card/Card.js The actual component
- frontend/src/components/Card/Card.module.css The styling of the card
How it works
The app renders a view, the view then calls a hook to get the data from the API, then passes the data into the card. While it waits for the data, the view shows "Laddar...", if something goes amiss it displays an error instead.
App → View → Hook (fetches data) → Card (displays data)
Example
<Card title="Temperature">
<p>{data.temperature} °C</p>
</Card>
Related Diagrams
For related diagrams see Frontend models.
A walkthrough of the Card component and an usage example
Components are JavaScript functions that return markup code. The use of JavaScript code lets us make components dynamic. To get started, lets look at Card.js:
import React from 'react';
import styles from './Card.module.css';
export default function Card({ title, children }) {
return (
<div className={styles.card}>
{title && <h3 className={styles.title}>{title}</h3>}
<div>{children}</div>
</div>
);
}
The Card function takes two props (parameters): { title, children }. Title is a string that gets displayed in an <h3>-tag:
<h3 className={styles.title}>{title}</h3>
The children prop is every child-node that gets passed to the Card function. To see how the function is used, let's look at TemperatureView.js:
import React from 'react';
import Card from '../../components/Card/Card';
import { useTemperature } from './useTemperature';
export default function TemperatureView() {
const { data, loading, error } = useTemperature();
if (loading) return <p>Laddar...</p>;
if (error) return <p>Fel: {error}</p>;
return (
<Card title="Temperatur">
<p style={{ fontSize: '2rem', fontWeight: 'bold', margin: 0 }}>
{data.temperature} °C
</p>
<p style={{ color: '#5d9e57', fontSize: '1rem', marginTop: '0.5rem' }}>
{new Date(data.timestamp).toLocaleString('sv-SE')}
</p>
</Card>
);
}
First of all we import the function:
import Card from '../../components/Card/Card';
Then we simple use it as if it were an HTML-tag.
<Card title="Temperatur">
...
</Card>
Here we see how both title and children parameters get passed to Card. Title is used like an attribute of the Card tag. Children is every child-node between the starting and closing tag of Card (the "..."). TemperatureView also makes use of an API-call through the useTemperature function. Let's take a look at that too.
import { useState, useEffect } from 'react';
const API_URL = '/api/temperature/latest';
export function useTemperature() {
const [data, setData] = useState(null); // { timestamp, temperature }
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch(API_URL)
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
})
.then(json => {
setData(json);
setError(null);
})
.catch(err => setError(err.message))
.finally(() => setLoading(false));
}, []);
return { data, loading, error };
}
Here we can see the use of react-hooks: useState and useEffect. Hooks are explained further down.
The basics are that useState returns a state variable and a setter. State variables are variables that when changed, cause a re-render of components that use the changed variable.
The useEffect hook allows code to be run after the site has finished rendering components, this is important when interacting with external systems. Without it, the entire site could wait for a single API to respond.
The useTemperature function uses both of these hooks, this allow it to make an API call after the site has finished rendering. Once the API has responded, it changes the state variables using the associated setter, which causes a re-render of components using those variables.
JSX (JavaScript XML)
[WIP]
Pure functions
Pure functions are functions that are deterministic and produce no side effects. In simpler terms it means that a function always returns the same value when given the same parameter. Think f(x) = 2x. f(2) will always equal to 4. No side effects means that the function doesn't change anything outside of itself. This means that a function can't access variables outside of its scope. React expects all components and effects to be written as pure functions. By doing this it can save time when re-rendering by skipping functions whose parameters (props) haven't changed.
Hooks
Hooks let you use different React features from your components. Here are some common ones:
useState(): The useState function returns a pair [state-variable, setter]. The setter should always be used to change the state. State variables have two main functions:
- Saving data between renders. When a re-render occurs, all local variables return to their initial values. useState lets components save and change data between renders. The component remembering data is useful for when changing something that needs the component to be rendered again, like changing what data is displayed.
- The setter causes a re-render. When data changes, we want to be able to see that. Updating a local variable doesn't change the look of the component. If for example the forecast gets updated, then the card containing that data should also be updated. Using the setter ensures that the new state gets shown on the site.
useContext(): Allows components to retrieve data from parents far up the component tree. You can for example get the current theme from the root element without having to pass it down as a prop to each and every component.. Context is created by using the createContext() function.
useEffect(): Simplified a bit from here. There are two types of logic in a react component:
- Rendering code, pure functions that run when the component is rendered and return HTML, and
- Event handlers, code nested inside component. This code is run when users interact with components and handles the user interaction by changing states and whatever.
Unlike rendering code and event handlers which are only executed on rendering and user interaction, useEffect allows a function to be run after react is finished rendering. It's mostly used when 'synchronizing' with external systems (e.g. fetching data from API) since it allows the website to be rendered before waiting on responses from external systems.
1. Setup
2. Standards
- Coding Conventions
- Issues
- Branch creation
- Reviews
- Implementation Standards
- [WIP] Creating new databases
- Localization
3. Models and Diagrams
4. Testing
5. Documentation
- Documentation for service endpoints
- API documentation
- Webpage Design
- Secrets and .env
- Evaluations
- Installation and Rebuild script documentation
6. Guides and How-to's
7. Micro Service Mockup Api
- Guidelines Mircro Service Mockup
- Documentation of useTemperature/useTemperatureTimeSeries mockup sensor