1.0.0 • Published 4 years ago

lanyage-react-hooks-demo v1.0.0

Weekly downloads
-
License
MIT
Repository
-
Last release
4 years ago

React在16.18之后hooks新特性

  • useState
  • useEffect
  • useContext
  • useReducer
  • useMemo
  • useCallback
  • useRef
  • 自定义hook

useState,

useState用于设置状态。

const [count, setCount] = useState({
  firstCount: initialCount1,
  secondCount: initialCount2
});

useEffect。

useEffect用于执行副作用操作,其第一个参数是一个函数,用于执行副作用操作,如:绑定事件,操作DOM,根据某个状态来执行异步操作;第二个参数是一个数组,表示依赖的状态,如不传,则表示只会在初始render时执行一次。另外,其return一个函数,并在该函数中释放资源,如停止定时任务。

// 操作DOM
useEffect(() => {
  console.log("use effect.");
  document.title = `count ${count}`;
}, [count]);

// 根据userId的变化来执行这个操作
const [useId, setUserId] = useState(1001);
useEffect(() => {
  // fetch, ajax, axios
}, [userId])

userContext

userContext类似于Java中的ThreadLocal,起到一个上下文的作用。

// producer
// App.jsx
export const XXXContext = React.createContext();
<XXXContext value={"xxx"}>
	<OtherComponent />
</XXXContext>

// consumer
import {useContext} from 'react';
import {XXXContext} from 'App';
const xxx = useContext(XXXContext);

useReducer

useReducer是useState的替代品,通过action来触发状态的变化。结合useContext可以实现属性代理

import {useReducer, useContext} from 'react';
const initialState = 0;
const reducer = (state, action) => {
  switch(action.type) {
    case "increment":
      return state + 1;
    default:
      return state;
  }
};

const [state, dispatch] = useReducer(reducer, initialState);
useEffect(() => {
  // fetch, axios, ajax
  fetch(`url`)
   .then(response => {
    	dispatch({type: 'SUCCSSS', payload: response});
  })
  .catch(err => {
    dispatch({type: 'ERROR'});
  })
}, [id])
useMemo

useMemo用于内存优化,将函数返回结果在内存缓存起来,如果没有变化,就不会重新计算。

const Counter = () => {
  const [count1, setCount1] = useState(0);
  const [count2, setCount2] = useState(0);

  // 当count1有变化,使用内存备忘录来记住count1计算出的值
  const isEven = useMemo( () => {
    let i = 0;
    while(i < 2000000000) i++;
    return count1 % 2 === 0;
  }, [count1]);

  return (
    <div>
      <div>
        <button onClick={() => {
          setCount1(d => d + 1);
        }}>Count1: {count1}</button>
        <span>{isEven ? "event" : "odd"}</span>
      </div>
      <div>
        <button onClick={() => {
          setCount2(d => d + 1);
        }}>Count1: {count2}</button>
      </div>
    </div>
  )
}
useCallback

React默认父组件的重新渲染会导致子组件的重新渲染。React在function的组件中,所有function都会在render时作为一个全新的function,但是大多数情况下我们不需要这样的函数,此时我们可以在组件上使用React.memo(component)并配合useCallback(() => {// change state code}, field), 这样可以减少很多自组件不必要的渲染。

import {useState, useMemo, useCallback} from 'react';

const Title = React.memo(function () {
  console.log('Rendering Title')
  return (
    <h2>
      useCallback Hook
    </h2>
  )
});

const Button = React.memo(
  function({ handleClick, children }) {
    console.log('Rendering button - ', children)
    return (
      <button onClick={handleClick}>
        {children}
      </button>
    )
  }
);

const Count = React.memo(
  function({ text, count }) {
	console.log(`Rendering ${text}`)
	  return <div>{text} - {count}</div>
  }
);


function ParentComponent() {
	const [age, setAge] = useState(25)
	const [salary, setSalary] = useState(50000)

	const incrementAge = useCallback(() => {
		setAge(age + 1)
	}, [age])

	const incrementSalary = useCallback(() => {
		setSalary(salary + 1000)
	}, [salary])

	return (
		<div>
			<Title />
			<Count text="Age" count={age} />
			<Button handleClick={incrementAge}>Increment Age</Button>
			<Count text="Salary" count={salary} />
			<Button handleClick={incrementSalary}>Increment Salary</Button>
		</div>
	)
}
useRef, 用于和DOM元素进行通信,或存储组件的某些属性如:this.xxx
// 和DOM元素通信
function FocusInput() {
	const inputRef = useRef(null)
	useEffect(() => {
		inputRef.current.focus()
	}, [])
	return (
		<div>
			<input ref={inputRef} type="text" />
		</div>
	)
}
// 存储组件属性
function HookTimer() {
  const [timer, setTimer] = useState(0)
  const interValRef = useRef()
  useEffect(() => {
    interValRef.current = setInterval(() => {
      setTimer(timer => timer + 1)
    }, 1000)
    return () => {
      clearInterval(interValRef.current)
    }
  }, [])
  return (
    <div>
      HookTimer - {timer} -
      <button onClick={() => clearInterval(interValRef.current)}>Clear Timer</button>
    </div>
  )
}
自定义hook,自定义hook本质上是对原生hook的一种封装。
// 例1
function useDocumentTitle(count) {
  useEffect(() => {
    document.title = `Count ${count}`
  }, [count])
}
// 例2
function useCounter(initialCount = 0, value) {
	const [count, setCount] = useState(initialCount)
	const increment = () => {
		setCount(prevCount => prevCount + value)
	}
	const decrement = () => {
		setCount(prevCount => prevCount - value)
	}
	const reset = () => {
		setCount(initialCount)
	}
	return [count, increment, decrement, reset]
}
// 例3
function useInput(initialValue) {
  const [value, setValue] = useState(initialValue)
  const reset = () => {
    setValue('')
  }
  const bind = {
    value,
    onChange: e => {
      setValue(e.target.value)
    }
  }
  return [value, bind, reset]
}

总结

如上就是React16.18之后提供的新特性,可以大大的减少代码量。