使用 React hooks 的注意事项

264 阅读1分钟

踩坑

import someFnComponent from './someFnComponent'

const [fnComponent, setFnComponent] = useState();

setFnComponent(someFnComponent )

//此时引入的函数组件props会失效。当引用时组件的props一直会是undefined。


const myFnCom = () => {
    return (
        <someFnComponent />
    )
} 

useState 部分源码分析:

const HooksDispatcherOnMount: Dispatcher = {
/** 省略其它Hooks **/
  useState: mountState,
};

// 所以调用useState()返回的就是HooksDispatcherOnMount.useState(),也就是mountState()

function mountState<S>(
  initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
    // 访问Hook链表的下一个节点,获取到新的Hook对象
  const hook = mountWorkInProgressHook();
//如果入参是function则会调用,但是不提供参数
  if (typeof initialState === 'function') {
    initialState = initialState();
  }
// 进行state的初始化工作
  hook.memoizedState = hook.baseState = initialState;
//这个initialSatet也会出现函数组件不能获取props的问题

//下面是更新state的函数

function updateReducer(reducer, initialArg, init) {
// 获取初始化时的 hook
  const hook = updateWorkInProgressHook();
  const queue = hook.queue;

  // 开始渲染更新
  if (numberOfReRenders > 0) {
    const dispatch = queue.dispatch;
    if (renderPhaseUpdates !== null) {
      // 获取Hook对象上的 queue,内部存有本次更新的一系列数据
      const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
      if (firstRenderPhaseUpdate !== undefined) {
        renderPhaseUpdates.delete(queue);
        let newState = hook.memoizedState;
        let update = firstRenderPhaseUpdate;
        // 获取更新后的state
        do {
          const action = update.action;
          // 此时的reducer是basicStateReducer,直接返回action的值
          newState = reducer(newState, action);
          update = update.next;
        } while (update !== null);
        // 对 更新hook.memoized 
        hook.memoizedState = newState;
        // 返回新的 state,及更新 hook 的 dispatch 方法
        return [newState, dispatch];
      }
    }
  }


// 对于useState触发的update action来说,basicStateReducer就是直接返回action(state)的值
这样也会造成props的丢失

function basicStateReducer<S>(state: S, action: BasicStateAction<S>): S {
  return typeof action === 'function' ? action(state) : action;
}

问题就出在了这里,如果传入的参数是函数,则会赋值,且提供state作为参数。

此时函数组件被传入当作普通函数。

然后赋值给newState

这时候如果把这个新的state当作函数组件使用,就会出现props丢失的问题。