# Hook --- What is Hook? --- Hooks are a fundamentally simpler way to encapsulate ==stateful== behavior and ==side effects== in user interfaces --- ```javascript=1 import React, { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); } ``` --- Deep dive: How do React hooks really work? --- build a Hooks clone in just ==29 lines== of readable JS --- It might just help your JS fundamentals if you go through this exercise. Don’t worry, ==it’s not that hard!== --- What is Closures? --- MDN: A closure is the combination of a ==function== bundled together (enclosed) with references to its ==surrounding state== (the lexical environment) --- The scope ```javascript=1 function foo() { let count = 0; console.log(count); } foo(); // 0 console.log(count); // ReferenceError: count is not defined ``` --- Scopes nesting ```javascript=1 function init() { var name = 'apa yu'; // local variable function displayName() { // displayName() is the inner function, a closure alert(name); // use variable declared in the parent function } displayName(); } init(); ``` --- 內層區塊可以存取定義在外層區塊的變數。反過來說,外層區塊沒辦法存取內層區塊的變數。 ~~你的就是我的,我的還是我的~~ --- 函式可以當成回傳值回傳 --- ```javascript=1 function init() { var name = 'apa yu'; // local variable function displayName() { // displayName() is the inner function, a closure alert(name); // use variable declared in the parent function } return displayName; } const sayHi = init(); sayHi(); ``` --- Closure 可以「保留」環境 --- so what? --- ```javascript=1 function makeAdder(x) { function add(y) { // closure return x + y; } return add; // return function } const add5 = makeAdder(5); // keep variable const add10 = makeAdder(10); // keep variable add5(2) // 7 add10(2) // 12 ``` --- ```javascript=1 function useState(initialValue) { var _val = initialValue; // local variable function state() { // closure return _val; } function setState(newVal) { // closure _val = newVal; } return [state, setState]; // return function } var [count, setCount] = useState(0); // keep variable console.log(count()); //0 setCount(1); console.log(count()); //1 ``` --- ~~fucntion~~ variable --- ```javascript=1 function useState(initialValue) { var _val = initialValue; // local variable // function state() { // closure // return _val; // } function setState(newVal) { // closure _val = newVal; } return [_val, setState]; // return variable and function } var [count, setCount] = useState(0); console.log(count); //0 setCount(1); console.log(count); //0 ?????????? ``` --- stale closure ```javascript=1 function createIncrement(i) { let value = 0; function increment() { value += i; console.log(value); const message = `Current value is ${value}`; return function logValue() { console.log(message); }; } return increment; } const inc = createIncrement(1); const log = inc(); // logs 1 inc(); // logs 2 inc(); // logs 3 // Does not work! log(); // logs "Current value is 1" ``` --- 解決方式A. Use a fresh closure ```javascript=1 const inc = createIncrement(1); inc(); // logs 1 inc(); // logs 2 const latestLog = inc(); // logs 3 // Works! latestLog(); // logs "Current value is 3" ``` --- 解決方式B. Close over the changed variable ```javascript=1 function createIncrementFixed(i) { let value = 0; function increment() { value += i; console.log(value); // const message = `Current value is ${value}`; return function logValue() { const message = `Current value is ${value}`; console.log(message); }; } return increment; } const inc = createIncrementFixed(1); const log = inc(); // logs 1 inc(); // logs 2 inc(); // logs 3 // Works! log(); // logs "Current value is 3" ``` --- ```javascript=1 const MyReact = (function() { let _val // hold our state in module scope return { render(Component) { const Comp = Component() Comp.render() return Comp }, useState(initialValue) { _val = _val || initialValue // assign anew every run function setState(newVal) { _val = newVal } return [_val, setState] } } })() ``` --- ```javascript=1 function Counter() { const [count, setCount] = MyReact.useState(0) return { click: () => setCount(count + 1), render: () => console.log('render:', { count }) } } let App App = MyReact.render(Counter) // render: { count: 0 } App.click() App = MyReact.render(Counter) // render: { count: 1 } ``` --- Deep dive: How do React hooks really work? https://www.netlify.com/blog/2019/03/11/deep-dive-how-do-react-hooks-really-work/ Be Aware of Stale Closures when Using React Hooks https://dmitripavlutin.com/react-hooks-stale-closures/ A Simple Explanation of JavaScript Closures https://dmitripavlutin.com/simple-explanation-of-javascript-closures/
{"metaMigratedAt":"2023-06-15T11:06:02.703Z","metaMigratedFrom":"Content","title":"Hook","breaks":true,"contributors":"[{\"id\":\"a1061309-7a7f-42b9-b144-e7e479bb7747\",\"add\":5938,\"del\":731}]"}
    166 views