aloerina01 / til

1日1つだけ強くなる
6 stars 0 forks source link

2019/01/29 ReactFiberのコードリーディング #95

Open aloerina01 opened 5 years ago

aloerina01 commented 5 years ago

react/ReactUpdateQueue.js at master · facebook/react

おそらく、段階的に画面が更新されてちらつくのを防ぐために、現在の状態とWorkInProgressの状態を比較して差分を出して、全てオフスクリーンで描画してから画面に一気に描画する、、、という感じのことをしている?それがダブルバッファリングということ?

export type Update<State> = {
  expirationTime: ExpirationTime,

  tag: 0 | 1 | 2 | 3,
  payload: any,
  callback: (() => mixed) | null,

  next: Update<State> | null,
  nextEffect: Update<State> | null,
};

updateオブジェクトがnextを持っている。この連結で順序を管理しているのでLinkedListということかな。

export type UpdateQueue<State> = {
  baseState: State,

  firstUpdate: Update<State> | null,
  lastUpdate: Update<State> | null,

  firstCapturedUpdate: Update<State> | null,
  lastCapturedUpdate: Update<State> | null,

  firstEffect: Update<State> | null,
  lastEffect: Update<State> | null,

  firstCapturedEffect: Update<State> | null,
  lastCapturedEffect: Update<State> | null,
};

Updateオブジェクトを持つキュー。firstUpdateとは、未消化の最初のUpdateオブジェクトを指すポインタ。lastUpdateはその名の通りキューの最後のUpdateオブジェクト。

キューの末尾に追加する処理(appendUpdateToQueue)を見ると分かりやすい。

function appendUpdateToQueue<State>(queue: UpdateQueue<State>, update: Update<State>,) {
  // Append the update to the end of the list.
  if (queue.lastUpdate === null) {
    // Queue is empty
    queue.firstUpdate = queue.lastUpdate = update;
  } else {
    queue.lastUpdate.next = update;
    queue.lastUpdate = update;
  }
}
aloerina01 commented 5 years ago

react/ReactFiber.js at master · facebook/react

react/ReactFiberReconciler.js at master · facebook/react

react/ReactFiberScheduler.js at master · facebook/react

aloerina01 commented 5 years ago

これだけ複雑だと「Hooksは魔法じゃない、ただの配列だ」とか言われても十分魔法に見えるんですが。

react/ReactFiberHooks.js at master · facebook/react

とりあえずuseReducerの中身のコアはこのへんっぽい

export function useReducer<S, A>(
  reducer: (S, A) => S,
  initialState: S,
  initialAction: A | void | null,
): [S, Dispatch<A>] {
  workInProgressHook = createWorkInProgressHook();
  let queue: UpdateQueue<S, A> | null = (workInProgressHook.queue: any);
  const dispatch: Dispatch<A> = (queue.dispatch: any);
  const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
  let update = firstRenderPhaseUpdate;
  do {
    const action = update.action;
    newState = reducer(newState, action);
    update = update.next;
  } while (update !== null);
  return [newState, dispatch];
}
aloerina01 commented 5 years ago

https://postd.cc/react-fiber-architecture/ react-fiber-architecture/README.md at master · acdlite/react-fiber-architectureの和訳あるの知らなかった、読む。

aloerina01 commented 5 years ago

That's the purpose of React Fiber. Fiber is reimplementation of the stack, specialized for React components. You can think of a single fiber as a virtual stack frame.

fiberを1つの(仮想)コールスタックだと考える、これはとてもしっくりきた。fiberが何なのかをイメージできないままにソースを読むと、どんな実装がなされているか予測できなくて苦戦したから。

aloerina01 commented 5 years ago

https://github.com/tranbathanhtung/react-fiber-implement

ここにFiberのキーワードと概要がメモされてて、いろいろ読んだ後だと理解を後押ししてくれる。初見だと何言ってるか分からなかったと思う

aloerina01 commented 5 years ago

react/ReactFiberScheduler.js at master · facebook/react

読み直し。 いろいろ読み解けてきた。