Add improved React notes

This commit is contained in:
thomasabishop 2022-07-12 15:42:08 +01:00
parent ebc82fbd8c
commit 86528ffa60
17 changed files with 1076 additions and 0 deletions

View file

@ -0,0 +1,51 @@
---
tags:
- Programming_Languages
- javascript
- react
---
# React application structure
When you use `create-react-app` it creates a default directory structure that is a sensible one to follow:
```
build/
public/
index.html
src/
index.js
App.js
```
## `public/`
- `public` constains the `index.html` file via which React connects to the traditional DCOM. Within `index.html` you have `<div id="root">...</div>` as the entry point where your application is injected into the standard DOM.
- Everything in this folder is as per standard web development practice.
- You shouldn't include React code here but you can paste necessary links and metadata to the `head` of `index.html`
## `src/`
- It automatically contains `index.js` . This imports `React` and `ReactDOM` and contains the `ReactDOM.render()` method:
```js
ReactDOM.render(
<App />
document.getElementById('root')
);
```
- The `App` component is your parent component and the container for your app. It is where you will import your sub-components.
- If you are using React Router `App` becomes the index for the different page components. See [Routing](./Routing.md) for more detail.
## `build`
`build` houses the compiled version of your application, ready to be deployed to a server. All contents are minified, compressed and optimised using Webpack.
Once you have executed `npm run build` you can test the output by using `serve` via the console:
```bash
serve -s build
```
`build` will comprise a minified version of `index.html` and a `static/` directory which holds your compiled CSS and JS that `index.html` links to, as per a standard static website.

View file

@ -0,0 +1,128 @@
---
tags:
- Programming_Languages
- javascript
- react
- react-classes
---
# Components and props with class-based components
A **component** is a class or a function that manages the content that is output on the page (the rendering of **elements**) and the data (**props**) and state that is applied to the elements that are output.
**Components can be created using ES6 classes or using the newer hook methodology.**
A class-based component is a mixture of standard Javascript, JSX Javascript and HTML wrapped within an extension of the `React.Component` **class** that you import into your custom JS when installing the React library:
```js
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
```
The JSX content of the component lives within the `render()` method that belongs to the `React.Component` class.
Once we have defined a class component that contains a JSX element we can then use JSX tags to place the resulting React element in our page. This is a placeholder for the HTML that is rendered by the class component. For example:
```html
<body>
<Welcome name="Thomas" />
</body>
```
> A class component must include `render()`, and the return can only return one parent element. Also there _must be_ a parent component. Where this isn't possible, the convention is to use empty opening and closing tags, viz: `<>...</>` . These are called **React Fragments** and this is actually a short hand for `<React.Fragment>...</React.Fragment>`
## Class components with state
Most class components will also possess state. State is managed through the constructor method on the class component, for example:
```jsx
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
```
We use the `super()` method to inherit the parent constructor (because custom components extend the React Component parent class) and we pass state as a special kind of prop.
## Class components and simple components
Within the class-based paradigm of React a distinction is made between simple and class components.
A class component is obviously a component that is created as a class and thus which can inherit fields and methods via `super` from the `React.Component` class. This is necessary for handling props and configuring state.
A simple component, in contrast, is a function, not a class. These are used for what we can call static or 'dumb' components, i.e they just output content and data, they don't have reactive state. This is why they are also sometimes called **functional stateless components**.
Simple components can however take props. In fact props are just like arguments that you pass to a function. When you write a simple component, your parameters are props.
Here's an example of a simple component that doesn't take any props
```jsx
function PageHeader() {
return (
<header>
<h1>Site Title</h1>
</header>
);
}
```
We can safely use arrow functions with simple components. So the same component could be written:
```jsx
const PageHeader = () => {
return (
<header>
<h1>Site Title</h1>
</header>
);
};
```
Now adding a prop:
```jsx
const PageHeader = (props) => {
return (
<header>
<h1>{props.sitename}</h1>
</header>
);
};
```
Then, in JSX we would apply the component with:
```jsx
<PageHeader sitename="The name of the site" />
```
> When we are using simple (functional) components we don't need to use `this.props` . `this` is only required with classes. As a simple component is a function we just say `props` .
It's worth noting in passing that you don't **have** to use functions for simple components. You can achieve the same outcome with a class and it won't generate an error. But it requires more code and complexity than is actually needed for the job:
```jsx
class PageHeader extends React.Component {
render() {
return (
<header>
<h1> {this.props.siteName} </h1>
</header>
);
}
}
export default PageHeader;
```

View file

@ -0,0 +1,134 @@
---
tags:
- Programming_Languages
- javascript
- react
- react-classes
---
# Managing forms with class components
We are going to create a simple form that takes two integers from input fields and returns their sum. Here is the raw component:
```jsx
class Form extends React.Component {
render() {
return (
<form>
<input type="number" placeholder="Please enter an integer" required />
<input type="number" placeholder="Please enter an integer" required />
<button>Calculate sum</button>
<output></output>
</form>
);
}
}
```
## Adding handlers
```jsx
class Form extends React.Component {
handleSubmit = (event) => {
event.preventDefault();
// Specific state change on submit
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="number" placeholder="Please enter an integer" required />
<input type="number" placeholder="Please enter an integer" required />
<button>Calculate sum</button>
<output></output>
</form>
);
}
}
```
- The overall handling of the form is going to execute on the submission of the form. So we create an `onSubmit` event within the form body and tie this to a handling function (`handleSubmit`) on the class.
- We follow the custom of generic naming of event methods with `handle[event]` , just like we use `handleClick` with `onClick` events
- The `event` object is a React wrapper for the standard DOM event. We operate on this object when managing the state of forms using React.
- `preventDefault` is just the React method of the traditional prevent default method that we can apply to forms. It stops the page updating when the submit button is clicked.
## Capturing input values through state change
In order to retrieve the values that the user enters we need to introduce state to the form component. This is managed using the `onChange` event. Even though the overall form action should be managed through `onSubmit` we need to initialize state on the inputs we intend to use when the form is submitted. This enshrines the React principle of **lifting state up**. As the `input` elements are constituents of the overall `form` component, their state should be handled by this common parent.
### Initializing `input` state with `onChange` events
To begin with let's just look at how we would do this in the abstract with a single `input` before applying it to the two inputs in our example:
```html
<input
type="number"
placeholder="Please enter an integer"
value="this.state.integerFirst"
onChange="this.handleChange"
required
></input>
```
We tie the state parameters in the `input` element to a `handleChange` function on the parent component but we first need to add the starting state (using `this.state` on the `Form` components' constructor:
```jsx
class Form extends React.Component {
constuctor(props) {
super(props);
this.state = {
integerFirst: " "
};
}
handleChange = (event) => {
this.setState(
{
integerFirst: event.target.value
}
}
```
Now the `Form` component is kept in the loop. Whenever the user alters the `input` field, this change will be logged as a state change within React. This will allow us to retrieve the values that the inputs have when the submit event fires.
## Handling multiple inputs
It would be inefficient to have a change handler for every input in a form with many inputs. In this scenario it is better to use destructuring to capture all the values:
```jsx
class Form extends React.Component {
constuctor(props) {
super(props);
this.state = {
integerFirst: "",
integerSecond: ""
};
}
returnSum = (x,y) => x + y;
handleSubmit = (event) => {
event.preventDefault()
this.setState({
outputSum: this.returnSum(
Number(this.state.integerFirst), Number(this.state.integerSecond)
)
});
handleChange = (event) => {
this.setState(
{
[event.targe.name]: value
}
)}
render() {
return(
<form onSubmit={this.handleSubmit}>
<input type="number" name="integerFirst" placeholder="Please enter an integer" onChange="this.handleChange" required />
<input type="number" name="integerSecond" placeholder="Please enter an integer" onChange="this.handleChange" required />
<button>Calculate sum</button>
<output></output>
</form>
)
}};
```

View file

@ -0,0 +1,58 @@
---
tags:
- Programming_Languages
- javascript
- react
---
# Lifecycle methods
Lifecycles are familiar from nature: something is born, it grows and reaches maturity and then dies and the process continues as what dies is broken down into constituent parts which form the basis of new life. And so on and so on.
The same metaphor can be applied to React components relative to the document object model:
- Components are 'born' (created and mounted on the DOM)
- They 'grow' by changing and updating their state
- They 'die' by being unmounted from the DOM
## Specific lifecycle phases
The outline above corresponds to specific methods that execute when React code runs:
1. `componentWillMount()` : this method is called just before the `render()` method is called
2. `componentDidMount()` : this method is called after the component is rendered in the DOM
The two methods above only occur once in a lifecycle.
The 'updating' phase is achieved with the following methods. This is when the data of the component, in the form of state and props updates in response to user interaction. We call this process 're-rendering':
3. `shouldComponentUpdate()` : determines whether component should update
4. `componentWillUpdate()` : called before re-rerendering occurs
5. `componentDidUpdate()` : called after re-rendering occurs
The final phase is unmounting: when the component is removed from the DOM:
6. `componentWillUnmount()`
![React component lifecycle](../../../img/react-lifecycle.png)
## Side-effects: why lifecycle phases matter
> React is built based on the principles of functional programming. In this paradigm, a side-effect (something that is generally discouraged) is any process that is not the direct result of a function executing or anything that is not covered by the `return` keyword.
Many of the methods detailed in the previous section will rarely be used in React development since they pertain to the inner engineering of the library, rather than its application in custom contexts. However sometimes you do need access to these methods, depending on the background context of what you are trying to achieving. This context could include external API and database requests or **anything that does not directly pertain to the rendering of the component on the screen**.
React groups these processes under the heading of **side-effects.**
### Examples of side-effects and where in the lifecycle they should run
- `componentWillMount` : It's a good idea to run set-up scripts at this point, such as connecting to and authenticating access to a database. This process runs before the `render` method is called so it is an optimal point to establish these connections
- You should not however make data requests at this point since data is typically returned asynchronously. You cannot therefore be sure that the data will be returned before mounting occurs.
- `componentDidMount` : This is the time to do things that can't occur without the DOM:
- retrieve data
- add event listeners
- set timers using `setTimeout` or `setInterval`
- Updating methods (`shouldComponentUpdate`, `componentWillUpdate` etc.)
- As these precede or take place concurrently with the rerendering process, this phase is a good point to retrieve new data or run necessary external processes that are required by the re-rendering.

View file

@ -0,0 +1,129 @@
---
tags:
- Programming_Languages
- javascript
- react
- react-classes
- react-hooks
---
# Comparing class components to hook-based components
We will look at the same component written with hooks and classes. Both use this child component:
```jsx
const CounterBox = (props) => {
return <div className="output">{props.counterValue}</div>;
};
```
## Class component
```jsx
import CounterBox from './CounterBox';
class CounterClass extends React.Component {
constructor(props) {
super(props);
this.state = {
counterValue: 0,
};
}
addOne() {
this.setState({
counterValue: this.state.counterValue + 1,
});
}
render() {
return (
<React.Fragment>
<button onClick={() => this.addOne()}>Add One</button>
<CounterBox counterValue={this.state.counterValue} />
</React.Fragment>
);
}
}
```
## Hook version
```jsx
import React, {useState} from 'react';
import CounterBox from './CounterBox';
function CounterHook() {
const [counter, setCounter] = useState(0);
const handleClick = () => setCounter(counter + 1);
return (
<React.Fragment>
<button onClick={handleClick}>Add One</button>
<CounterBox counterValue={counter}></CounterBox>
</React.Fragment>
);
}
```
## Main differences
- Obviously with hooks we use a function, not a class. We can therefore think of them as **simple components** that are able to handle state as well as props.
- We have written the hook as a declared function but we could just as easily write it as a function expression or arrow function.
- With the class, the state versioning is managed via the following properties on the `React.Component` class: `this.state` (start state) and `this.setState` (the change).
- In both cases the function that actually creates the change is handled via an arrow function. With the hook we use the customary name `handleClick` .
- The same process is managed in the hook via the `useState()` method. We effectively set 'before' and 'after' destructured variables on this method:
```jsx
const [counter, setCounter] = useState(0);
// Schematically:
const [val, setVal] = useState(initialVal);
```
## Binding with class component state
In the class component example we use an inline arrow function to execute `addOne()` however the official way to do it is to bind the event via the constructor method to avoid the problems created by `this` scope in classes. Using arrows is mostly fine and is less verbose, but it is important to understand the 'official' approach.
The way to write the state change in this way is:
```jsx
class CounterClass extends React.Component{
constructor(props){
super(props);
this.state = { counterValue: 0};
this.handleClick = this.handleClick.bind(this); // bind the click to the class scope
}
handleClick(event){
this.setState({
counterValue: this.state.counterValue + 1;
});
}
render(){
return (
<button type="button"
onClick={this.handleClick}> // reference the class scope with `this`
Click Me
</button>
<CounterBox counterValue={this.state.counterValue}></CounterBox>
);
}
}
```
## How hooks improve on class components
- State, when managed via hooks can be easily decoupled from a specific component and reused elsewhere. This also means it can be tested separately from any specific component where it is applied. This is much harder to do with classes which are closely entangled with the non-state aspects of a component through `this` and binding:
> With Hooks, you can extract stateful logic from a component so it can be tested independently and reused. Hooks allow you to reuse stateful logic without changing your component hierarchy. This makes it easy to share Hooks among many components or with the community.
- Hooks simplify lifestyle methods and the use of `componentDidMount` etc through the `useEffect` hook
- Classes and `this` are confusing generally. Functions are easier to grasp and read.
## Relation to function components
You can think of hooks as function components (previously known as stateless components) plus state. Previously function components were 'dumb' components. That is, they didn't allow for state management and generally used for layout. They could receive data as props but not state. This changes with hooks: you can add state to functions and no longer need to use classes exclusively for state. In fact you no longer need to use classes at all, unless you want to.
> The stateful portion of a function component must be placed before the `return()` statement in the function.

View file

@ -0,0 +1,16 @@
---
tags:
- Programming_Languages
- javascript
- react
---
# Controlled components
Controlled components relate to how you use forms in React.
You can use standard form HTML within a React component but applying React state to the form via controlled components gives you greater power over what you do with the inputs and how you handle the data that is received.
Standard HTML forms have a separate state from the rest of the document object and this is highly mutable. It can send requests to a server and reload the page. This mutability can obviously interfere with the state you maintain in your React components; this is why it is best to manage form state along with React state.
We can combine the two [native HTML form state and React state] by making the React state be the “single source of truth”. Then the React component that renders a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a “controlled component”.

View file

@ -0,0 +1,17 @@
---
tags:
- Programming_Languages
- javascript
- react
- react-hooks
---
# Errors
## State update on unmounted component
> Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
This typically happens when you have an API request running in the background. Once the data is returned, React tries to update the state but the component is unmounted.
As the warning suggests, this can be resolved using the cleanup parameter within [useEffect](../../Programming_Languages/React/Hooks/useEffect.md#cleanup-functions).

View file

@ -0,0 +1,64 @@
---
tags:
- Programming_Languages
- javascript
- react
- react-hooks
---
# Components and props with hooks
As of React 16.8 a class component can be expressed using a function-based hook.
A class component:
```jsx
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
```
The same component expressed as a hook:
```jsx
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
```
To output this component we use the same standard JSX syntax and pass the prop as an attribute of the JSX element:
```jsx
<Welcome name="Thomas" />
```
## How hooks are rendered
1. We call `ReactDOM.render()` with the `<Welcome name="Thomas" />` element. (This would typically be nested within a root `App` component; it wouldn't be directly passed to the parent render function.)
2. React calls the `Welcome` component with `{name: 'Thomas'}` as the props.
3. Our `Welcome` component returns a `<h1>Hello, Thomas</h1>` element as the result.
4. React DOM efficiently updates the DOM to match `<h1>Hello, Thomas</h1>`.
## Function components must be pure functions
> All React components must act like pure functions with respect to their props
This means that functions should not attempt to change the inputs they receive as parameters. They must always return the same result for the same inputs:
```jsx
function sum(a, b) {
return a + b;
}
```
```jsx
function withdraw(account, amount) {
account.total -= amount;
}
```
The reason for this is that **props are read-only** and we pass props to function components.
We change components by using state, not by mutating props. This is consistent with React's [principle of the immutability of elements](https://www.notion.so/Elements-992594b9cd2e483c85cddddffeb16f11).

View file

@ -0,0 +1,120 @@
---
tags:
- Programming_Languages
- javascript
- react
- react-hooks
---
# Iterating through data
As React follows the **functional programming paradigm** and state versioning, looping is not the recommended way of engineering repeated processes since it presupposes pre-existing state. Instead React relies on the functional methods of modern JavaScript such as `map` , `filter` , `reduce` to output the values of iterative data structures.
Instead of mutating the state of a reference type, these methods are 'non-destructive': they create a new array that meets the requirements set in the particular method. These newly created arrays and objects therefore form the basis of the state versioning, because each new array that is engendered, is a new state configuration.
## The `key` attribute
The `key` attribute is a special React attribute that should be added to the elements of any listed content (i.e numbered lists, unordered lists, `select` options etc; basically anything rendered that comes about through mapping arrays and objects).
This enables React to monitor the state of the list: which items have changed, been added, or removed.
The best way to pick a key is to use a string that uniquely identifies a list item among its siblings.
For instance, using our earlier `numbers` array, assuming each number is unique, we could use the number itself as the key:
```jsx
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) => <li key={number.toString()}> {number}</li>);
```
> Keys have to be unique to the individual element and not shared by any other sibling. But they do not need to be globally unique. You could use the same `key` name in another array list.
> Keys should be string types, not other data types. You can use the `.toString()` method to ensure this is the case.
If you can't find a unique basis for naming a series of keys, you can use the `index` value of the `Array.map` function. This should only be used if the order of the items doesn't change. An example:
```jsx
class List extends React.Component {
render() {
const demoArr = ["cat", "dog", "mouse"];
return (
<ul>
{demoArr.map((x, index) => (
<li key={index}>{x}</li>
))}
</ul>
</div>
);
}
}
```
## Demonstration
### Source data
```jsx
const blogData = [
{
id: 1,
date: '2020-11-15',
title: 'Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum.',
shortByline:
'Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. ',
longByline:
'Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor.',
image: blogImage,
},
{
id: 2,
date: '2020-08-11',
title: 'Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum.',
shortByline:
'Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. ',
longByline:
'Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor.',
image: blogImage,
},
];
```
### Child component
```jsx
export default function BlogPreviewCard(props) {
return (
<Card>
<CardMedia image={props.image} />
<CardContent>
<Typography>{props.date}</Typography>
<Typography>{props.title}</Typography>
<Typography>{props.shortByline}</Typography>
</CardContent>
<CardActions>
<Button>Read</Button>
</CardActions>
</Card>
);
}
```
### Iteration
```jsx
// This uses the Material-UI grid component
import BlogPreviewCard from "../components/BlogPreviewCard"
import blogData from "../data/blogData
export default function BlogPreviewSet() {
return (
<Grid>
{blogDummyData.map((data, index) => (
<Grid key={index}>
<BlogPreviewCard key={index} {...data} />
</Grid>
))}
</Grid>
)
}
```

View file

@ -0,0 +1,70 @@
---
tags:
- Programming_Languages
- javascript
- react
- react-hooks
---
# `useCallback`
In short, React's useCallback hook is used to wrap functions. It tells React to not re-create a wrapped function when a component re-renders, unless any of the useCallback's dependencies change.
`useCallback` returns a memoized version of the callback function it is passed. This means that the function object returned from useCallback will be the same between re-renders.
Remember that in JavaScript, functions are objects. As a result, every time a component containing a function re-renders, it creates a new instance of the function in memory. If a function doesn't change in response to a UI event throughout the lifecycle of the component, there is no need for it to rerender, hence `useCallback` should be applied.
> Given the same dependency value, the `useCallback` hook returns the same function instance between renderings (aka memoization).
This said, for small functions that are not intensive, it doesn't really matter if they are not memoized.
## Syntax
A standard case of this would be a function that runs on a button click, for instance when sending data from a form to a server. In the example below there is quite a lot going on, and most of it is independent of the actual UI-cycle of the component.
```jsx
const handleSubmit = useCallback(
async (formValues) => {
setPendSaveConfig(true);
const payload = new GenerateConfig({
workflowId: project_id,
blockId: blockId,
config: formValues,
});
axios
.post(`${process.env.REACT_APP_ENDPOINT}/save-block-config`, payload)
.then((res) => console.log(res))
.finally(() => setPendSaveConfig(false))
.catch((err) => console.error(err));
},
[blockId, project_id],
);
```
Note that the syntax is similar to [useEffect](./useEffect.md): there is a dependency array. The effect is the same: the function contained within `useCallback` will only re-rendered if one of these dependencies changes. However (see next section) the function will run in its memoized form on every click.
## Reference versus result
`useCallback` only memoizes the function _object_ (the reference) not the value that is _returned_ by the function (the result).
In the example below, the `calculatePi()` function reference will not change between renders but each time the click event fires, the value returned by `calculatePi()` will change. In other words, it will be assigned fresh memory.
```jsx
function ParentComponent() {
const onHandleClick = useCallback(() => {
const special = calculatePi();
});
return <SubComponent handleClick={onHandleClick} />;
}
```
## Use cases
You should not apply `useCallback` in a blanket fashion, this can reduce performance rather than improve it. The best scenarios are:
1. A functional component wrapped inside React.memo() accepts a function object prop
2. When the function object is a dependency to other hooks, e.g. `useEffect(..., [callback])`
3. When the function has some internal state, e.g. when the function is debounced or throttled.

View file

@ -0,0 +1,92 @@
---
tags:
- Programming_Languages
- javascript
- react
- react-hooks
---
# `useEffect`
`useEffect` should be used for any background process that does not arise as a result of a user interaction or standard state change. The canonical example would be dispatching a request to an API to retrieve data to display in a component's initial render.
`useEffect` enshrines but also simplifies the [lifecyle methods](./../Classes/Lifecycle_methods.md) that are used with class-based React components.
## Demonstration
```jsx
const [workflowTitle, setWorkflowTitle] = useState('');
const [loading, setLoading] = useState(false);
useEffect(() => {
const fetchWorkflowTitle = () => {
axios
.post(`${process.env.REACT_APP_ENDPOINT}/load-workflows`, {
workflow_id: project_id,
user_id: isAuth?.userId,
})
.then((res) => {
setWorkflowTitle(res?.data?.meta.name);
})
.finally(() => setLoading(false))
.catch((err) => {
console.error(err);
});
};
setLoading(true);
fetchWorkflowTitle();
}, [project_id, isAuth]);
```
In this example we fetch some data from a REST API and store the response value as state, which can then be accessed within our JSX template.
## Function placement
In the example, the function is declared inside of the `useEffect` hook and then called. We do this to avoid adding the function to the dependency array, which we couldn't do if we defined it outside of the hook, somewhere in the component. If we did this, the function would run on every render by default and would be recalled again because of its placement in the dependency array, which leads to the 'too many rerenders' error.
An alternative would be to define it outside of the component itself but this is difficult since it requires state from the component to run.
## Dependency array
Note the array that is the second argument to `useEffect`. This is the **dependency array** and is how we manage the lifecycle of the side-effect.
- After the initial call on render, the function within the `useEffect` block will run any time one of the dependencies update. The dependency array typically refers to variables that are defined within the hook but can also contain references to variables outside of it.
- If you do not include the array, the effect runs on every render
- If you pass an empty array, the effect will only run once on the initial render
## Cleanup functions
The syntax of the `useEffect` hook also allows you to handle cleanup: something you want to do when the component unmounts (another example of how this hook recasts the traditional [lifecycle methods](./../Classes/Lifecycle_methods.md)) . In addition to running on unmount, the cleanup function will run before the effect runs again (i.e. when it runs in response to a change in one of the elements of the dependency araray). This is chiefly used to prevent [memory leaks](../../../Software_Engineering/Memory_leaks.md) and the ['update on unmounted component error'](../Errors.md#state-update-on-unmounted-component).
You do this by having a `return` clause after the main effect. Schematically:
```js
useEffect(() => {
// Run your effect;
return () => {
// Put your cleanup function here
};
}, [input]);
```
Here is an example of using a cleanup to cancel a subscription
```js
useEffect(() => {
let isApiSubscribed = true;
axios.get(API).then((response) => {
if (isApiSubscribed) {
// handle success
}
});
return () => {
isApiSubscribed = false;
};
}, []);
```
## Resources
[Understanding the React useEffect cleanup function](https://blog.logrocket.com/understanding-react-useeffect-cleanup-function/)

View file

@ -0,0 +1,78 @@
---
tags:
- Programming_Languages
- javascript
- react
- react-hooks
---
# `useState`
`useState` is the primary way in which React updates the application state based on user interaction.
- `useState` **receives**: the initial state as an argument
- `useState` **returns**: the current state and a function that updates it
The two items that are returned are returned as an array. We could refer to them with array syntax (i.e with `[0]` and `[1]` ) but it is more concise to use the destructuring syntax. But all that's happening is that a method belonging to the `React` library (i.e. `useState` ) is taking an argument (the initial state) and returning two values as an array of two elements. The first of these values is a variable, the second is a function.
```jsx
(1) const [count, setCount] = useState(0);
(2) const handleClick = () => { setCount(count + 1) };
(3) <span>{count}</span>
(4) <button onClick={handleClick)>Add one</button>
```
- At line 1 we initialise the `useState` hook.
- We use destructuring syntax to declare two variables
- The first variable stores our initial state. The value of the initial state is an argument passed to `useState` , i.e. `0`. Do not confuse the variable with the value it refers to.
- The second variable is a method that mutates the state referred to by the first variable into some new value, i.e. from `0` to a different integer
- At line 3, which in reality, will be within your JSX and part of the `render()` block of the function, we render the initial state in the React DOM. This will change and be re-rendered in accordance with the state logic
- At line 4 we have a user interface that executes the function on line 2. This function applies the state change represented by the second variable in the destructuring assignment at line 1 (`setCount` ): it mutates the initial state (`0`) by the value of `1'.
> You can utilise as many `useState` declarations as your component requires.
## Passing variables as initial state
We don't always have to declare the data types within the destructuring assignment. We can store them in variables and pass the variables to the destructuring assignment on `useState` . Below we do this for a function that mutates a string value:
```jsx
const hi = "hello";
const bye = "goodbye";
const [initText, changeText] = useState(hi);
<p>{initText}</p>
<button onClick={()=>changeText(bye)}>ChangeText</button>
```
## Lazily setting initial state
Although you will typically use a literal value or variable as your initial state, React provides a way for you to set this value through a function. This will only run once at the first render so as not to interfere with the second update parameter of `useState`. This is called **lazy initialisation**
```jsx
const getInitialState = () => Number(window.localStorage.getItem('count'));
const [count, setCount] = React.useState(getInitialState);
```
## Accessing previous state
It is also possible to access the previous state via the `useState` hook. We can access this as a callback on the updater function.
Let's say we have a simple counter set up like so:
```js
const [count, setCount] = useState(0);
```
We can access the prior value of `count` with:
```js
const getPrevValue = () => setCount((prev) => console.log(prev));
```
### Naming best practise
When destructuring the two variables from `useState`, React follows uses the following semantics: `[something, setSomething]` . This isn't required but it helps to keep everything clear, particularly the fact that the first thing destructured is a variable and the second is a function.
> https://stackoverflow.com/questions/54807454/what-is-prevstate-in-reactjs

View file

@ -0,0 +1,106 @@
---
tags:
- Programming_Languages
- javascript
- react
- data-types
---
# Prop types
**The `prop-types` package allows us to introduce type-checking during the development runtime of a React application. With larger applications or those with complex data flows, this can help reduce errors and bugs during development. This is a bit like using TypeScript but on a more minimal level.**
## Install
```
npm install prop-types
```
## Usage
```jsx
import PropTypes from 'prop-types';
```
## Examples
Say we have a component with the following props:
```jsx
function Page(props) {
const classes = useStyles();
return (
<React.Fragment>
<Typography className={classes.heading} variant="h1">
{props.h1}
</Typography>
{props.h2 !== '' && <Typography variant="h2">{props.h2}</Typography>}
{props.paras.map((paragraph, index) => (
<Typography className={classes.paragraph} key={index} variant="body1" gutterBottom>
{paragraph}
</Typography>
))}
{props.children}
<Button
className={classes.button}
variant="contained"
color="primary"
disableElevation
component={Link}
to={props.buttonLink}
>
{props.buttonText}
</Button>
</React.Fragment>
);
}
```
Before the final `export default` statement, we would add a PropTypes object that specifies the data or reference type that is required by each prop cited in the component:
```jsx
Page.propTypes = {
h1: PropTypes.string.isRequired, // should be string data type, must be present
h2: PropTypes.string, // as above but optional
paras: PropTypes.array, // should be array reference type
buttonLink: PropTypes.string,
buttonText: PropTypes.string,
children: PropTypes.node, // can be anything (element, type, JSX) that is rendered to the screen
};
```
If one of these type checks failed you get a very semantic Warning in the console specifying which prop is not consistent with your prop type declaration.
## Additional checks
Above are the most frequent and basic checks, but there are many other conditions you can check for:
```jsx
// The full list of types
[propName]: PropTypes.array,
[propName]: PropTypes.bool,
[propName]: PropTypes.func,
[propName]: PropTypes.number,
[propName]: PropTypes.object,
[propName]: PropTypes.string,
[propName]: PropTypes.symbol,
// Anything that can be rendered: numbers, strings, elements or an arrayor fragment) containing these types.
[propName]: PropTypes.node,
// A function
[propName]: PropTypes.func
// An object that could be one of many types
[objectProp]: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
// An array of a certain type
[arrayProp]: PropTypes.arrayOf(PropTypes.number),
// An object with property values of a certain type
[objectProp]: PropTypes.objectOf(PropTypes.number),
```

View file

@ -0,0 +1,5 @@
# React TypeScript Learning Resources
https://www.toptal.com/react/react-hooks-typescript-example
https://react-typescript-cheatsheet.netlify.app/

View file

View file

@ -0,0 +1,8 @@
---
tags:
- Software_Engineering
---
# Memory leaks
A memory leak occurs when you program memory and forget to delete it once you are finished. The consequences of memory leak is that it reduces the performance of the computer by reducing the amount of available memory. Eventually, in the worst case, too much of the available memory may become allocated and all or part of the system or device stops working correctly, the application fails, or the system slows down vastly .