This page was saved using WebZIP 7.0.3.1030 offline browser on 12/02/19 14:55:01.
Address: http://www.zhufengpeixun.cn/ahead/html/69-hooks.html
Title: 珠峰架构师成长计划  •  Size: 55444  •  Last Modified: Sun, 01 Dec 2019 11:37:11 GMT

1. React Hooks #

2. 注意事项 #

3. 搭建项目 #

npx create-react-app zhufeng_hooks
cd zhufeng_hooks
yarn start

4. useState #

const [state, setState] = useState(initialState);

4.1 使用useState #

src\index.js

import React,{useState} from 'react';
import ReactDOM from 'react-dom';
function Counter(){
    const [number,setNumber] = useState(0);
    return (
        <>
            <p>{number}</p>
            <button onClick={()=>setNumber(number+1)}>+</button>
        </>
    )
}
function render(){
    ReactDOM.render(<Counter/>,document.getElementById('root'));
}
render();

4.2 实现useState #

src\index.js

import React from 'react';
import ReactDOM from 'react-dom';
let memoizedState;
function useState(initialState){
    memoizedState = memoizedState||initialState;
    function setState(newState){
       memoizedState = newState;
       render();
    }
    return [memoizedState,setState];
}

function Counter(){
    const [number,setNumber] = useState(0);
    return (
        <>
            <p>{number}</p>
            <button onClick={()=>setNumber(number+1)}>+</button>
        </>
    )
}
function render(){
    ReactDOM.render(<Counter/>,document.getElementById('root'));
}
render();

5. useReducer #

5.1 使用useReducer #

import React,{useReducer} from 'react';
import ReactDOM from 'react-dom';
const initialArg = 0;

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {number: state.number + 1};
    case 'decrement':
      return {number: state.number - 1};
    default:
      throw new Error();
  }
}
function init(initialArg){
    return {number:initialArg};
}
function Counter(){
    debugger;
    const [state, dispatch] = useReducer(reducer, initialArg,init);
    return (
        <>
          Count: {state.number}
          <button onClick={() => dispatch({type: 'increment'})}>+</button>
          <button onClick={() => dispatch({type: 'decrement'})}>-</button>
        </>
    )
}
function render(){
    ReactDOM.render(<Counter/>,document.getElementById('root'));
}
render();

5.2 实现useReducer #

import React from 'react';
import ReactDOM from 'react-dom';
let memoizedState ;
function useReducer(reducer, initialArg,init){
     var initialState = void 0;
      if (init !== undefined) {
        initialState = init(initialArg);
      } else {
        initialState = initialArg;
      }
      function dispatch(action){
          memoizedState = reducer(memoizedState,action);
          render();
      }
      memoizedState =  memoizedState||initialState;
      return  [memoizedState, dispatch];
}
const initialArg = 0;

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {number: state.number + 1};
    case 'decrement':
      return {number: state.number - 1};
    default:
      throw new Error();
  }
}
function init(initialArg){
    return {number:initialArg};
}
function Counter(){
    debugger;
    const [state, dispatch] = useReducer(reducer, initialArg,init);
    return (
        <>
          Count: {state.number}
          <button onClick={() => dispatch({type: 'increment'})}>+</button>
          <button onClick={() => dispatch({type: 'decrement'})}>-</button>
        </>
    )
}
function render(){
    ReactDOM.render(<Counter/>,document.getElementById('root'));
}
render();

5.3 useReducer实现useState #

import React from 'react';
import ReactDOM from 'react-dom';
let memoizedState;
function useReducer(reducer, initialArg,init){
     var initialState = void 0;
      if (init !== undefined) {
        initialState = init(initialArg);
      } else {
        initialState = initialArg;
      }
      function dispatch(action){
          memoizedState = reducer(memoizedState,action);
          render();
      }
      memoizedState =  memoizedState||initialState;
      return  [memoizedState, dispatch];
}
function useState(initialState){
    return  useReducer((oldState, newState)=>newState, initialState);
}

function Counter(){
    const [number,setNumber] = useState(0);
    return (
        <>
            <p>{number}</p>
            <button onClick={()=>setNumber(number+1)}>+</button>
        </>
    )
}
function render(){
    ReactDOM.render(<Counter/>,document.getElementById('root'));
}
render();

6. 多个useState #

6.1 使用 #

import React,{useState} from 'react';
import ReactDOM from 'react-dom';


function Counter(){
    const [name,setName] = useState('计数器');
    const [number,setNumber] = useState(0);
    return (
        <>
            <p>{name}:{number}</p>
            <button onClick={()=>setName('计数器'+Date.now())}>修改名称</button>
            <button onClick={()=>setNumber(number+1)}>+</button>
        </>
    )
}
function render(){
    ReactDOM.render(<Counter/>,document.getElementById('root'));
}
render();

6.2 实现 #

import React from 'react';
import ReactDOM from 'react-dom';

let memoizedStates = [];
let index = 0;
function useState(initState){
    memoizedStates[index]=memoizedStates[index]||initState;
    const currentIndex = index;
    function setState(newState){
        memoizedStates[currentIndex] = newState;
        render();
    }
    return [memoizedStates[index++],setState];
}


function Counter(){
    const [name,setName] = useState('计数器');
    const [number,setNumber] = useState(0);
    return (
        <>
            <p>{name}:{number}</p>
            <button onClick={()=>setName('计数器'+Date.now())}>修改名称</button>
            <button onClick={()=>setNumber(number+1)}>+</button>
        </>
    )
}
function render(){
    index = 0;
    ReactDOM.render(<Counter/>,document.getElementById('root'));
}
render();

7. useEffect #

useEffect(didUpdate);

7.1 使用useEffect #

import React,{useState,useEffect} from 'react';
import ReactDOM from 'react-dom';

function Counter(){
    const [name,setName] = useState('计数器');
    const [number,setNumber] = useState(0);
    useEffect(() => {
        console.log(number);
     }, [number]);
    return (
        <>
            <p>{name}:{number}</p>
             <button onClick={()=>setName('计数器'+Date.now())}>修改名称</button>
            <button onClick={()=>setNumber(number+1)}>+</button>
        </>
    )
}
function render(){
    ReactDOM.render(<Counter/>,document.getElementById('root'));
}
render();

7.2 实现useEffect #

import React,{useState} from 'react';
import ReactDOM from 'react-dom';
let lastDependencies;
function useEffect(callback,dependencies){
  if(!dependencies) return callback();  
  let changed = lastDependencies?!dependencies.every((item,index)=>item===lastDependencies[index]):true;
  if(changed){
    callback();
    lastDependencies=dependencies;
  }
}
function Counter(){
    const [name,setName] = useState('计数器');
    const [number,setNumber] = useState(0);
    useEffect(() => {
        console.log(number);
     }, [number]);
    return (
        <>
            <p>{name}:{number}</p>
             <button onClick={()=>setName('计数器'+Date.now())}>修改名称</button>
            <button onClick={()=>setNumber(number+1)}>+</button>
        </>
    )
}
function render(){
    ReactDOM.render(<Counter/>,document.getElementById('root'));
}
render();
import React,{useState} from 'react';
import ReactDOM from 'react-dom';
let lastDependencies;
let unEffect;
function useEffect(callback,dependencies){
   unEffect&&unEffect();
   if(!dependencies){
       unEffect = callback();
       return;
   }
   let changed = lastDependencies? !dependencies.every((item,index)=>item===lastDependencies[index]):true;
   if(changed){
    unEffect = callback();
    lastDependencies = dependencies;
   } 
} 
function Counter(){
     let [name,setName] = useState('计数器');
    let [number,setNumber] = useState(0);
    useEffect(()=>{
        let $timer = setInterval(() => {
            setNumber(number+1);
        }, (1000));
        return ()=>{
            clearInterval($timer);
        }
    },[number]);
    return (
        <>
          <p>{name}:{number}</p>
          <button onClick={()=>setName('计数器'+Date.now())}>改名称</button>
          <button onClick={()=>setNumber(number+1)}>+</button>
        </>
    )
}
function render(){
    ReactDOM.render(<Counter />, document.getElementById('root'));
}
render();

7.3 useState+useEffect #

import React from 'react';
import ReactDOM from 'react-dom';
let memoizedStates = [];
let index = 0;
function useState(initState){
    memoizedStates[index]=memoizedStates[index]||initState;
    const currentIndex = index;
    function setState(newState){
        debugger;
        memoizedStates[currentIndex] = newState;
        render();
    }
    return [memoizedStates[index++],setState];
}

function useEffect(callback,dependencies){
  if(!dependencies) {
      index++;
      return callback();  
  }
  const lastDependencies = memoizedStates[index];
  let changed = lastDependencies?!dependencies.every((item,index)=>item===lastDependencies[index]):true;
  if(changed){
    callback();
    memoizedStates[index]=dependencies;
  }
  index++;
}
function Counter(){
    const [name,setName] = useState('计数器');
    const [number,setNumber] = useState(0);
    useEffect(() => {
        console.log(number);
     }, [number]);
    return (
        <>
            <p>{name}:{number}</p>
             <button onClick={()=>setName('计数器'+Date.now())}>修改名称</button>
            <button onClick={()=>setNumber(number+1)}>+</button>
        </>
    )
}
function render(){
    index = 0;
    ReactDOM.render(<Counter/>,document.getElementById('root'));
}
render();

8. useState源码中的链表实现 #

import React from 'react';
import ReactDOM from 'react-dom';

let firstWorkInProgressHook={memoizedState: null,next: null};
let workInProgressHook=firstWorkInProgressHook;

function useState(initState){
    let currentHook = workInProgressHook.next?workInProgressHook.next:{memoizedState: initState,next: null};
    function setState(newState){
        currentHook.memoizedState = newState;
        render();
    }
    if(workInProgressHook.next){
        workInProgressHook = workInProgressHook.next;
    }else{
        workInProgressHook.next = currentHook;
        workInProgressHook = currentHook;
    }
    return [currentHook.memoizedState,setState];
} 

function Counter(){
    const [name,setName] = useState('计数器');
    const [number,setNumber] = useState(0);
    return (
        <>
            <p>{name}:{number}</p>
            <button onClick={()=>setName('新计数器'+Date.now())}>新计数器</button>
            <button onClick={()=>setNumber(number+1)}>+</button>
        </>
    )
}
function render(){
    workInProgressHook = firstWorkInProgressHook;
    ReactDOM.render(<Counter/>,document.getElementById('root'));
}
render();