# 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).