React Hooks常用的Hooks钩子函数

React Hooks的作用是对函数型组件进⾏增强,让函数型组件可以存储状态, 可以拥有处理副作⽤的能⼒,可以在不使⽤类组件的情况下, 实现相同的功能。

useState实现原理

useState方法接收参数,可以是普通值,也可以接收函数做为参数,如果是函数做为参数,组件初始化时会调用函数,返回的结果就时初始状态值;useState方法调用返回数组,数组参数为状态值跟改变状态值的方法;useState使用闭包的方式存储状态,能多次调用,因此需要外部声明数组变量存储状态值跟方法,并添加索引;当调用更改状态方法时重新渲染

let state = [];
let setters = [];
let stateIndex = 0;

function createSetter (index) {
  return function (newState) {
    state[index] = newState;
    render ();
  }
}

function useState (initialState) {
  state[stateIndex] = state[stateIndex] ? state[stateIndex] : initialState;
  setters.push(createSetter(stateIndex));
  let value = state[stateIndex];
  let setter = setters[stateIndex];
  stateIndex++;
  return [value, setter];
}

function render () {
  stateIndex = 0;
  effectIndex = 0;
  ReactDOM.render(<App />, document.getElementById('root'));
}

useEffect实现原理

useEffect是实现类组件当中生命周期函数的钩子。useEffect执行时机,传入空数组([]),组件初始化执行一次,同类组件componentDidMount;不传第二个参数时,组件初始化执行,组件更新也会执行,同类组件componentDidMount,componentDidUpdate;当useEffect传入的函数返回一个函数时,返回的函数执行时机会在组件卸载之后执行,同类组件的componentWillUnmount生命周期。当useEffect的第二个参数传入参数时,值发生变化,函数也会执行。useEffect同样也能多次调用。代码实现:

// 上一次的依赖值
let prevDepsAry = [];
let effectIndex = 0;

function useEffect(callback, depsAry) {
  // 判断callback是不是函数
  if (Object.prototype.toString.call(callback) !== '[object Function]') throw new Error('useEffect函数的第一个参数必须是函数');
  // 判断depsAry有没有被传递
  if (typeof depsAry === 'undefined') {
    // 没有传递
    callback();
  } else {
    // 判断depsAry是不是数组
    if (Object.prototype.toString.call(depsAry) !== '[object Array]') throw new Error('useEffect函数的第二个参数必须是数组');
    // 获取上一次的状态值
    let prevDeps = prevDepsAry[effectIndex];
    // 将当前的依赖值和上一次的依赖值做对比 如果有变化 调用callback
    let hasChanged = prevDeps ? depsAry.every((dep, index) => dep === prevDeps[index]) === false : true;
    // 判断值是否有变化
    if (hasChanged) {
      callback();
    }
    // 同步依赖值
    prevDepsAry[effectIndex] = depsAry;
    effectIndex++;
  }
}

useReducer实现原理

useReducer接收两个参数,第一个是reducer函数,第二个为初始状态值。useReducer调用返回数组,数组第一个值是状态值,第二个是dispatch方法。
代码实现:

function useReducer (reducer, initialState) {
  const [state, setState] = useState(initialState);
  function dispatch (action) {
    const newState = reducer(state, action);
    setState(newState);
  }
  return [state, dispatch];
}

上面是一些常用钩子的实现原理,下面是组件其他拓展钩子的使用方法

useContext

useContext在跨组件层级获取数据时简化获取数据的代码,实现跨组件间的通信;
通过creactContext方法调用返回的对象中的Provider包裹需要传值的组件,后辈组件通过useContext钩子调用creactContext方法返回的对象,获取到传递的值;
没有useContext之前需要通过creactContext方法返回对象的Consumer获取。

import { creactContext, useContext } from 'react'
const countContext = creactContext();
function App() {
	return <countContext.Provider value={100}>
		<Foo />
	</countContext.Provider>
}
funtion Foo() {
	const count = useContext(countContext)
	return <div>{count}</div>
}

不使用useContext获取

import { creactContext, useContext } from 'react'
const countContext = creactContext();
function App() {
	return <countContext.Provider value={100}>
		<Foo />
	</countContext.Provider>
}
funtion Foo() {
	return <countContext.Consumer>
		{
			(count)=> <div>{count}</div>
		}
	</countContext.Consumer>
}

useMemo

useMemo 的⾏为类似Vue中的计算属性, 可以监测某个值的变化, 根据变化值计算新值;useMemo 会缓存计算结果. 如果监测值没有发⽣变化, 即使组件重新渲染, 也不会重新计算. 此⾏为可以有助于避免在每个渲染上进⾏昂贵的计算

import { useMemo } from 'react'

const result = useMemo(() => {
	// 如果count值发生变化函数重新执行
	return result
}, [count])

memo方法和useCallback

memo跟useCallback都属于优化组件性能的方法,memo 类似类组件中的 PureComponent 和 shouldComponentUpdate,如果组件中的数据没有发⽣变化, 阻⽌组件更新;useCallback的作用缓存函数, 使组件重新渲染时得到相同的函数实例
下面案例通过useCallback缓存setCount方法,子组件在触发事件时,通过memo调用后就不会重新渲染;如果不执行useCallback直接将setCount传给子组件,子组件虽然调用了memo方法,但是会在重新渲染时认为传入的值发生了变化,所以会重新渲染,useCallback就完美规避的这个问题

import React, { useCallback, setCount } from 'react'

function Counter() {
	const [count, setCount] = useState(0);
	const resetCount = useCallback(() => setCount(0), [setCount]);
	return <div>
		<span>{count}</span>
		<button onClick={() => setCount(count + 1)}>+1</button>
		<Test resetCount={resetCount} />
	</div>
}
//Test
import { memo } from 'react'

function Test (props) => {
	console.log('Test re-render');
	return <div>
		<button onClick={props.resetCount}>reset</button>
	</div>
}
export default memo(Test)

useRef

useRef可以获取DOM元素对象,同时还可以保存数据,即使组件重新渲染, 保存的数据仍然还在,保存的数据被更改不会触发组件重新渲染;useRef调用返回一个对象,存储的数据存放在对象的current属性中

import React, { useRef } from 'react'

function App() {
	const username = useRef();
	const handler = () => console.log(username); //{ current: input }
	return <input ref={username} onChange={handler} />
}

自定义Hook

⾃定义 Hook 是标准的封装和共享逻辑的⽅式;⾃定义 Hook 是⼀个函数, 其名称以 use 开头;⾃定义 Hook 其实就是逻辑和内置 Hook 的组合

function useUpdateInput (value) {
	const [value, setValue] = useState(value)
	return {
		value,
		onChange: event => setValue(event.target.value)
	}
}

function App(){
	const usernameInput = useUpdateInput('');
	const passwordInput = useUpdateInput('');
	const submitForm = event => {
		event.preventDefault();
		console.log(usernameInput.value);
		console.log(passwordInput.value);
	}
	return <form onSubmit={submitForm}>
		<input type="text" name="username" {...usernameInput }/>
		<input type="password" name="password" {...usernameInput }/>
		<input type="submit"/>
	</form>
}

React 路由 Hooks

react-router-dom 路由提供了4个钩⼦函数,用于获取路由信息
React Hooks常用的Hooks钩子函数_第1张图片
文章为个人学习笔记记录心得,有错误欢迎指正

你可能感兴趣的:(javascript,react.js)