# Function Conversion
## Part One: Initial Conversion
### 1. Change Class to Function
**Class-based component**
In a class-based component, the component is defined using the `class` keyword and extends `React.Component`. For example:
```jsx
class MyComponent extends React.Component {
// ...
}
```
**Functional component**
To convert this to a functional component, you can change the `class` keyword to a `function` or an arrow function. Here's an example using an arrow function:
```jsx
const MyComponent = (props) => {
// ...
}
```
### 2. Remove the render method
**Class-based component**
In a class-based component, you need to define a `render` method that returns the JSX to be rendered. For example:
```jsx
class MyComponent extends React.Component {
render() {
return <div>Hello, World!</div>;
}
}
```
**Functional component**
In a functional component, you don't need a separate `render` method. Instead, you can keep everything after and including the `return` statement from the `render` method and remove the rest of the `render` method. Here's an example:
```jsx
const MyComponent = (props) => {
return <div>Hello, World!</div>;
}
```
### 3. Convert all methods to functions
**Class-based component**
In a class-based component, you can define methods that can be called from within the component. For example:
```jsx
class MyComponent extends React.Component {
handleClick() {
console.log('Clicked!');
}
render() {
return <button onClick={this.handleClick}>Click me!</button>;
}
}
```
**Functional component**
In a functional component, you don't have methods, but you can still define functions inside the component. Convert all methods to functions (closures) by removing the `this` keyword and changing the function declaration syntax. Here's an example:
```jsx
const MyComponent = (props) => {
const handleClick = () => {
console.log('Clicked!');
}
return <button onClick={handleClick}>Click me!</button>;
}
```
### 4. Remove references to `this`
**Class-based component**
In a class-based component, you use the `this` keyword to access props and state. For example:
```jsx
class MyComponent extends React.Component {
render() {
return <div>{this.props.message}</div>;
}
}
```
**Functional component**
In a functional component, you don't use the `this` keyword. Instead of using `this.props`, you can use the `props` parameter directly. Here's an example:
```jsx
const MyComponent = (props) => {
return <div>{props.message}</div>;
}
```
## Part Two: State Management
### 5. Use the useState hook to manage state
**Class-based component**
In a class-based component, you can use the `this.state` and `this.setState` to manage state. For example:
```jsx
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
handleClick = () => {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={this.handleClick}>
Click me
</button>
</div>
);
}
}
```
**Functional component**
In a functional component, you can use the `useState` hook to manage state. The `useState` hook returns an array with two elements: the current state value and a function to update the state. Here's an example:
```jsx
import * as React from 'react';
const MyComponent = (props) => {
const [count, setCount] = React.useState(0);
const handleClick = () => {
setCount(count + 1);
}
return (
<div>
<p>You clicked {count} times</p>
<button onClick={handleClick}>
Click me
</button>
</div>
);
}
```
### 6. Use the useEffect hook for side effects
**Class-based component**
In a class-based component, you can use lifecycle methods like `componentDidMount`, `componentDidUpdate`, and `componentWillUnmount` to perform side effects. For example:
```jsx
class MyComponent extends React.Component {
componentDidMount() {
console.log('Component mounted');
}
componentDidUpdate() {
console.log('Component updated');
}
componentWillUnmount() {
console.log('Component will unmount');
}
render() {
// ...
}
}
```
**Functional component**
In a functional component, you can use the `useEffect` hook to perform side effects. The `useEffect` hook takes two arguments: a function that performs the side effect and an array of dependencies. Here's an example:
```jsx
import * as React from 'react';
const MyComponent = (props) => {
React.useEffect(() => {
console.log('Component mounted or updated');
return () => {
console.log('Component will unmount');
}
}, []);
// ...
}
```
### 7. Timers
**Class-based component**
In a class-based component, you can use the `componentDidMount` and `componentWillUnmount` lifecycle methods to set up and clean up a timer. Here’s an example:
```jsx
class Timer extends React.Component {
state = { count: 0 };
componentDidMount() {
this.intervalId = setInterval(() => {
this.setState({ count: this.state.count + 1 });
}, 1000);
}
componentWillUnmount() {
clearInterval(this.intervalId);
}
render() {
return <div>{this.state.count}</div>;
}
}
```
In this example, we use the `setInterval` function to increment the `count` state every second when the component mounts. When the component unmounts, we use the `clearInterval` function to clear the interval.
**Functional component**
In a functional component, you can use the `useEffect` hook to set up and clean up a timer. Here’s an example:
```jsx
import * as React from 'react';
const Timer = (props) => {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
const intervalId = setInterval(() => {
setCount((c) => c + 1);
}, 1000);
return () => {
clearInterval(intervalId);
};
}, []);
return <div>{count}</div>;
};
```
In this example, we use the `setInterval` function to increment the `count` state every second. When the component unmounts, we use the cleanup function returned by the `useEffect` hook to clear the interval using the `clearInterval` function.
## Part Three: State Management Across Pages
### 8. Providers
TODO
### 9. Redux
In a class-based component, you can use the `connect` function from the `react-redux` library to connect your component to the Redux store. Here's an example of a class-based component connected to the Redux store:
```jsx
import * as React from 'react';
import { connect } from 'react-redux';
class MyComponent extends React.Component {
render() {
const { count, increment } = this.props;
return (
<div>
<div>{count}</div>
<button onClick={increment}>Increment</button>
</div>
);
}
}
const mapStateToProps = (state) => ({
count: state.count,
});
const mapDispatchToProps = (dispatch) => ({
increment: () => dispatch({ type: 'INCREMENT' }),
});
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
```
In this example, we use the `connect` function to connect the `MyComponent` class-based component to the Redux store. The `mapStateToProps` function maps the `count` state from the Redux store to the `count` prop of the `MyComponent` component. The `mapDispatchToProps` function maps the `increment` action creator to the `increment` prop of the `MyComponent` component.
In a functional component, you can use the `useSelector` and `useDispatch` hooks from the `react-redux` library to access the Redux store. Here's an example of how you could convert the above class-based component to a functional component:
```jsx
import * as React from 'react';
import { useSelector, useDispatch } from 'react-redux';
const MyComponent = (props) => {
const count = useSelector((state) => state.count);
const dispatch = useDispatch();
const increment = () => {
dispatch({ type: 'INCREMENT' });
};
return (
<div>
<div>{count}</div>
<button onClick={increment}>Increment</button>
</div>
);
};
export default MyComponent;
```
In this example, we use the `useSelector` hook to access the `count` state from the Redux store and the `useDispatch` hook to dispatch actions to the Redux store. The `increment` function dispatches an `INCREMENT` action to the Redux store when called.
### 10. Redux decorators
TODO
## Part Four: Testing
TODO
## Part Five: Performance
### Understanding Rendering in React
When a component’s state or props change, React updates the user interface by rerendering the component. This means that React calls the component’s `render` method or `function body` to figure out what the component should look like. The result is a lightweight description of the user interface, called a React element.
React then compares the new React element with the previously rendered one to figure out what changes need to be made to the actual user interface. This process is called reconciliation. Once React has figured out what changes need to be made, it applies them to the user interface in batches to improve performance.
### Unnecessary Rerendering in React
In React, when a component's state or props change, the component is rerendered. However, sometimes a component can be rerendered even if its state or props haven't actually changed. This can happen when the component's props are complex objects, like arrays or objects.
For example, let's say we have a `Child` component that receives an object prop called `data` from its parent component:
```jsx
const Child = ({ data }) => {
console.log('Child rendered');
return <div>{data.value}</div>;
};
const Parent = () => {
const [data, setData] = useState({ value: 0 });
const handleClick = () => {
setData({ value: data.value + 1 });
};
return (
<>
<Child data={data} />
<button onClick={handleClick}>Increment</button>
</>
);
};
```
In this example, the `Parent` component has a `data` state that is an object with a `value` property. When the `Increment` button is clicked, the `handleClick` function is called and updates the `data` state by creating a new object with the updated `value`.
However, even though we're creating a new object with the same properties as the previous one, React will still consider this a change and rerender the `Child` component. This is because React uses a shallow comparison to check if the props have changed. A shallow comparison only checks if the references to the objects are the same, not if their properties are the same.
This behavior is similar to how JavaScript compares objects using the `==` or `===` operators. In JavaScript, when you compare two objects using these operators, it returns `true` only if the two objects refer to the same object in memory. This means that even if two objects have the same properties and values, they are still considered different if they refer to different objects in memory.
Let's say we have two objects `a` and `b` defined as follows:
```javascript
const a = { x: 1 };
const b = { x: 1 };
```
Even though both `a` and `b` have the same property `x` with the same value `1`, if we compare them using the `==` or `===` operators, it will return `false`:
```javascript
console.log(a == b); // false
console.log(a === b); // false
```
This is because `a` and `b` refer to different objects in memory, even though they have the same properties and values.
To prevent unnecessary rerenders in this situation, we can use memoization techniques like `React.memo` and `React.useCallback`. These techniques allow us to tell React when it should consider two objects to be equal and avoid rerendering the component.
### Optimizing Performance with Memoization in React
In React, a component rerenders whenever its state or props change. This can lead to unnecessary rerenders if the component's state or props haven't actually changed. To prevent unnecessary rerenders, you can use the `React.memo` higher-order component and the `React.useCallback` hook.
#### React.memo
The `React.memo` higher-order component is used to memoize a functional component. This means that if the component's props haven't changed, React will reuse the last rendered result instead of calling the component again. Here's an example of how you could use `React.memo`:
```jsx
import * as React from 'react';
const MyComponent = React.memo((props) => {
console.log('MyComponent rendered');
return <div>{props.count}</div>;
});
const ParentComponent = (props) => {
const [count, setCount] = React.useState(0);
return (
<div>
<MyComponent count={count} />
<button onClick={() => setCount((c) => c + 1)}>Increment</button>
</div>
);
};
```
In this example, the `MyComponent` functional component is wrapped with `React.memo`. This means that if the `count` prop passed to `MyComponent` hasn't changed, React will reuse the last rendered result instead of calling `MyComponent` again.
#### React.useCallback
The `useCallback` hook is used to memoize a callback function. This means that if the dependencies of the callback function haven't changed, React will reuse the same function instance instead of creating a new one. Here's an example of how you could use `useCallback`:
```jsx
import * as React from 'react';
const MyComponent = (props) => {
console.log('MyComponent rendered');
return <div>{props.count}</div>;
};
const ParentComponent = (props) => {
const [count, setCount] = React.useState(0);
const increment = React.useCallback(() => {
setCount((c) => c + 1);
}, []);
return (
<div>
<MyComponent count={count} />
<button onClick={increment}>Increment</button>
</div>
);
};
```
In this example, the `increment` callback function is memoized using the `useCallback` hook. This means that if the dependencies of the `increment` function (in this case, none) haven't changed, React will reuse the same function instance instead of creating a new one.
### When to Avoid Memoization in React
Memoization can be a powerful tool for optimizing the performance. However, it's important to use it judiciously and only when necessary. Here are some situations where you should avoid using memoization:
#### 1. When the cost of memoization outweighs the benefits
Memoization comes with a cost: it requires additional memory to store the memoized values and additional computation to check if the dependencies have changed. If the cost of memoizing a value or function outweighs the performance benefits, you should avoid using memoization.
For example, if you have a simple component that renders quickly and doesn't have any expensive calculations, it might not be worth memoizing it using `React.memo`. Similarly, if you have a simple callback function that doesn't do any expensive calculations, it might not be worth memoizing it using `useCallback`.
#### 2. When the dependencies change frequently
Memoization is most effective when the dependencies of the memoized value or function don't change frequently. If the dependencies change frequently, the memoized value or function will be recomputed on every render, negating any performance benefits.
For example, if you have a component that depends on a prop that changes frequently, it might not be worth memoizing it using `React.memo`. Similarly, if you have a callback function that depends on a state or prop that changes frequently, it might not be worth memoizing it using `useCallback`.
#### 3. When the dependencies are complex objects
Memoization relies on checking if the dependencies have changed using a shallow comparison. This means that if the dependencies are complex objects (e.g., arrays or objects), changes to their properties won't be detected by the shallow comparison.
For example, if you have a component that depends on an array prop and you mutate the array instead of creating a new one, `React.memo` won't detect the change and won't rerender the component. Similarly, if you have a callback function that depends on an object state and you mutate the object instead of creating a new one, `useCallback` won't detect the change and will reuse the old function instance.
In these situations, you should either avoid using memoization or make sure to create new objects or arrays when their properties change.