# React Hooks
[Hooks FAQ](https://reactjs.org/docs/hooks-faq.html)
#### Class component [不好用的原因](https://reactjs.org/docs/hooks-intro.html)
* 比function需要更多syntax
* 機器跑起來較慢
* interfere with certain React tools and feature
#### React Hook 可以讓function component使用state和管理side effect(取代Class component)
* 在state改變時管理state跟rendering
* Provide access to app's component
* Update component with an alternative to lifecycle method
## [useState](https://reactjs.org/docs/hooks-state.html)
You use Hooks inside functions only (Hooks don't work inside classes), so `this` is not available inside a function component. Instead, you use the [`useState`](https://reactjs.org/docs/hooks-reference.html#usestate) Hook for state management.
* `useState()` is the equivalent of both `this.state` and `this.setState` for function components.
```
import React, { useState } from 'react';
function App() {
const [ score, setScore ] = useState(0); // [0, ƒ]
return (
...
);
}
```
1. import useState from React
2. declare a state variable by calling `useState()` (示範的`score`)
3. one optional argument – the initial value of the state variable.(示範的`0`)
Calling useState() with the initial state returns an array with two values:
第一個是 current state value (示範的`0`). It's similar to `this.state`.
第二個是 function to update that value, and it's similar to `this.setState()`.
* React Hook使用[解構賦值](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)來給變數賦值.(示範的`score` `setScore`)
* In class components, the state always has to be an object. With **useState()** state can be an object, array, or another JavaScript primitive like a string or integer.
#### Update State
```
return (
<div className="App">
<header className="App-header">
<h1>{ score }</h1>
<button onClick={() => setScore(score + 1)}> // update the score state
Increase score
</button>
</header>
</div>
);
```
必須使用function setScore來改變score
#### Declare Multiple States
```
function App() {
const [ score, setScore ] = useState(0);
const [ message, setMessage ] = useState('Welcome!');
return (
...
);
}
```
#### Update State Based on Previous State
If you need to update state using the previous state value, you can pass a function to the method updating state. The function receives the previous state value and uses it to return the updated value.
```
function Counter({initialCount}) {
const [count, setCount] = useState(initialCount);
return (
<>
Count: {count}
<button onClick={() => setCount(initialCount)}>Reset</button>
<button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
</>
);
}
```
## [useEffect](https://reactjs.org/docs/hooks-effect.html)
#### side effects
there are different phases in a React component's lifecycle: *mounting*, *updating*, and *unmounting*. React provides lifecycle methods to run code at these specific moments. They are used to
* re-render a component
* update the DOM when data changes
* fetch data from an API
* perform any necessary cleanup when removing a component.
Developers refer to these types of actions as **side effects** because you cannot perform them during rendering (additional code runs after React updates the DOM).
#### Lifecycle methods React uses to handle side effects in class components:
`componentDidMount`, `componentDidUpdate`, and `componentWillUnmount`. Forgetting to include one of these methods when needed, can leave us with stale data or [memory leaks](https://teamtreehouse.com/library/prevent-memory-leaks-with-componentwillunmount).
#### Perform Side Effects in Function Components
`useEffect` Hook: class components的side effects handler三合一.
```
function App() {
const [score, setScore] = useState(0);
const [message] = useState('Welcome!');
useEffect(() => {
document.title = `${message}. Your score is ${score}`;
}, [message, score]); // add dependencies
return (...);
}
```
1. The `useEffect` Hook instructs React to do something after render
參數1:**callback function** 執行side effects
參數2(optional): **dependencies** array, 如果dependencies沒變則skip applying an effect,
* dependencies (避免沒必要的re-render)
any **state variables** that are used or updated inside `useEffect`.
**Tips**: 放空`[]`,`useEffect`只會在initial render後執行一次
2. 可以Access State variable (包括更新的state) Inside `useEffect`
範例為state改變時更新title,此時`score` `message`是dependencies, 所以要放入dependencies array
**Note**: 如果沒放會收到console warning.
#### Data Fetching with `useEffect`
[axios](https://github.com/axios/axios)
```
function App() {
const [data, setData] = useState('');
useEffect(() => {
console.log('useEffect called!');
fetch('https://dog.ceo/api/breeds/image/random')
.then(res => res.json())
.then(data => setData(data.message))
.catch(err => console.log('Oh noes!', err))
}, []);
return (
<div className="App">
<img src={data} alt="A random dog breed" />
</div>
);
}
```
In some cases, omitting dependencies array causes `useEffect()` to execute in an infinite loop, endlessly fetching data. This happens because you're *modifying the component's state*(`setState()`) inside `useEffect()`.
3. **Tip**: [Use Multiple Effects to Separate Concerns](https://reactjs.org/docs/hooks-effect.html#tip-use-multiple-effects-to-separate-concerns)
#### "Clean Up" `useEffect`
With Hooks, you don't need a separate function to perform cleanup. Returning a function from your effect takes care of the [cleanup](https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup), running the function when the component unmounts.
## [useContext](https://reactjs.org/docs/hooks-reference.html#usecontext)
Provides the functionality of the Context API in a single function. Once you've created your app's Context, call [`useContext()`](https://beta.reactjs.org/reference/react/useContext#updating-data-passed-via-context) inside a function component to access any Context state and actions.
#### Use Context in the Component
基本設定:
```
//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from './Components/Context'; //context管理員
import App from './Components/App';
import './index.css';
ReactDOM.render(
<Provider> //注意context provider被包在最上層
<App />
</Provider>,
document.getElementById('root')
);
```
```
//Provider Component (context管理員)
import React, { useState } from 'react';
export const ScoreboardContext = React.createContext() //提供contect object
export const Provider = (props) => {
const [players, setPlayers] = useState([]);
... // The players state and event handlers 放在這個檔案裡
}
```
讓component訂閱資料:
```
//要使用context的component
import React, { useContext } from 'react';
import { ScoreboardContext } from './Context'; //導入context object
const PlayerList = () => {
const { players } = useContext(ScoreboardContext); //從context object解構賦值取出context的資料
...
}
```
如此`PlayerList` Component is now subscribed to any context changes,且當context value changes時會re-render
#### Access State and Actions in the Component
```
//Access "players" state且the 使用removePlayer action(event handlers被放在context管理員裡)
import React, { useContext } from 'react';
import { ScoreboardContext } from './Context'; //同上
const Player = ({ index }) => {
const { players, actions } = useContext(ScoreboardContext); //從context object解構賦值取出players state跟actions
return (
<div className="player">
<span className="player-name">
<button
className="remove-player"
onClick={() => actions.removePlayer(players[index].id)}>✖ //Call the removePlayer action with actions.removePlayer
</button>
{ players[index].name }
</span>
<Counter index={index} />
</div>
);
};
```
## Next Steps
[Hooks API Reference](https://reactjs.org/docs/hooks-reference.html) | [Hooks FAQ](https://reactjs.org/docs/hooks-faq.html)
#### Additional Hooks
React provides [additional built-in Hooks](https://reactjs.org/docs/hooks-reference.html#additional-hooks) besides `useState`, `useEffect`, and `useContext`.
* [`useReducer`](https://reactjs.org/docs/hooks-reference.html#additional-hooks)
Can help when dealing with complex state logic or when the next state depends on the previous state.
* [`useRef`](https://reactjs.org/docs/hooks-reference.html#useref)
Provides an easier way to access DOM nodes or React elements created in the render method with a ref attribute.
* [`useHistory`](https://reactrouter.com/web/api/Hooks/usehistory)
Which is imported from React Router Dom and provides access to the history object.
#### [Custom Hooks](https://reactjs.org/docs/hooks-custom.html)
With custom Hooks, you can reuse logic easily, share information across components and write less code. Like built-in Hooks, custom Hooks are JavaScript functions whose names start with `use`.
#### Rules of Hooks
There are [**two main rules**](https://reactjs.org/docs/hooks-rules.html) you should follow when using Hooks:
1. Call Hooks **only at the top level of your React function**. For example, don't call Hooks inside loops, conditions, or nested functions.
2. Call Hooks from React **function components only**. Hooks do not work inside class components.
React provides a handy ESLint plugin called `eslint-plugin-react-hooks` to help enforce these rules. This plugin is included by default in [Create React App](https://teamtreehouse.com/library/using-create-react-app).