独自のライブラリを作成
22658 ワード
ソース:https://pomb.us/build-your-own-react/に入る前に. x 結果?JavaScriptで記述されたレスポンスコード 「どうする?」『あなた自身の反応』を見てフォローし、知りたい部分は学習整理 💡 目次
**Step I**: The `createElement` Function
**Step II**: The `render` Function
**Step III**: Concurrent Mode
**Step IV**: Fibers
**Step V**: Render and Commit Phases
**Step VI**: Reconciliation
**Step VII**: Function Components
**Step VIII**: Hooks
1. createElement Function
DOMノード を作成 props を追加
生成ノードをコンテナ に追加する.3.同時モード
要素をDOMの に追加元素を製造する子供が添加する繊維 次の勤務先を選択します. fiber - children - ling - parent
繊維樹の目的は、次の作業単位を見つけやすいことです.
1本の繊維が仕事を終えると、子供がいれば、兄弟姉妹は次の職場になります.
兄弟姉妹がいない場合は、ルートに戻るまで親に表示されます.
5. Render and Commit
タイプが同じならアイテムのみ交換-update タイプは異なり、新しい要素であり、新しいDOMノードを生成します.placement タイプは異なり、古いファイバがある場合は古いノードを削除- を削除
削除するノードを追跡する代理配列を作成します.
commitRootでdelegation配列を巡回してcommitWorkを実行します.commitWork関数では、effectTag追加、removeChildまたはupdateを使用します.
更新のために
従来の繊維の支柱と新繊維の支柱とを比較し,消失した支柱を取り除き,異なる支柱を設けた.onで始まるprops(event)がある場合はeventListenerを追加します.
7.関数構成部品
Reactの要素はReactです.createElement関数を使用して作成されますが、読みやすさが悪いため、JSX構文を使用します.JSX構文はbabelからJSに変換されます. 反応は、繊維樹構造を用いて作業単位を構造化する. virtual DOMは、render関数によって得られる要素、すなわちJavaScriptオブジェクトである.反応器は前の木と新しい木を同時に巡回して比較した.
**Step I**: The `createElement` Function
**Step II**: The `render` Function
**Step III**: Concurrent Mode
**Step IV**: Fibers
**Step V**: Render and Commit Phases
**Step VI**: Reconciliation
**Step VII**: Function Components
**Step VIII**: Hooks
1. createElement Function
JSX —babel—> React.createElement
reactの要素はreactです.createElement関数を使用して作成されますが、読みやすさが悪いため、JSX構文を使用します.JSX構文はbabelからJSに変換されます.React.createElement
function createElement(type,props,...children){ // (type,props,[children])
return {
type,// tag name
props:{
...props,
children
}
}
}
// text를 처리하기 위한 함수
function createTextElement(text) {
return {
type: 'TEXT_ELEMENT',
props: {
nodeValue: text,
children: []
}
};
}
💡 突然のクイック演算子!
...子供は子供という配列要素のスプレッドシートです.したがって、type、props、および[children]になります.
2. render Function ReactDOM.render
function createElement(type,props,...children){ // (type,props,[children])
return {
type,// tag name
props:{
...props,
children
}
}
}
// text를 처리하기 위한 함수
function createTextElement(text) {
return {
type: 'TEXT_ELEMENT',
props: {
nodeValue: text,
children: []
}
};
}
ReactDOM.render
生成ノード
function render(element,container){
const dom =
element.type == "TEXT_ELEMENT"
? document.createTextNode("") // text node
: document.createElement(element.type) // element type으로 DOM노드 생성하기
const isProperty = key => key !== 'children'
// element에 props 추가
Object.keys(element.props)
.filter(isProperty)
.forEach(name => {
dom[name] = element.props[name]
})
// children을 재귀적으로
element.props.children.forEach(child=>
render(child,dom)
)
container.appendChild(dom) // 생성한 node container에 추가
}
3.同時モード
レンダー関数の再帰呼び出しセクションでは、ツリーの最後にレンダリングされるまで操作を停止しません.ツリーが大きくなると、メインスレッドは長い間停止します.ブラウザは、レンダリングを停止して優先度の高いタスクを処理する必要があります.function render(element, container) {
...
element.props.children.forEach((child) => render(child, dom));
container.appendChild(dom);
}
したがって、タスクを小さなセルに分割し、各セルが完了した後にブラウザにレンダリングを停止させます.let nextUnitOfWork = null
function workLoop(deadline) {
let shouldYield = false
while (nextUnitOfWork && !shouldYield) {
nextUnitOfWork = performUnitOfWork(
nextUnitOfWork
)
shouldYield = deadline.timeRemaining() < 1
}
requestIdleCallback(workLoop)
}
requestIdleCallback(workLoop)
function performUnitOfWork(nextUnitOfWork) {
// TODO
}
requestIdleCallback:requestIdleCallback loopを作成するために使用します.ブラウザのプライマリ・スレッドがアイドル状態の場合、requestIdleCallbackが呼び出されます.
4. Fibers
各作業単位を構造化するためには、fiber tree
の資料構造が必要である.
上記の操作を行うと、render関数の内部にルートファイバが作成され、nextUnitOfWorkに設定されます.残りの作業はperformUnitOfWork
機能で発生します.
繊維ごとに3つのことをします.
function render(element, container) {
...
element.props.children.forEach((child) => render(child, dom));
container.appendChild(dom);
}
let nextUnitOfWork = null
function workLoop(deadline) {
let shouldYield = false
while (nextUnitOfWork && !shouldYield) {
nextUnitOfWork = performUnitOfWork(
nextUnitOfWork
)
shouldYield = deadline.timeRemaining() < 1
}
requestIdleCallback(workLoop)
}
requestIdleCallback(workLoop)
function performUnitOfWork(nextUnitOfWork) {
// TODO
}
各作業単位を構造化するためには、
fiber tree
の資料構造が必要である.上記の操作を行うと、render関数の内部にルートファイバが作成され、nextUnitOfWorkに設定されます.残りの作業は
performUnitOfWork
機能で発生します.繊維ごとに3つのことをします.
繊維樹の目的は、次の作業単位を見つけやすいことです.
1本の繊維が仕事を終えると、子供がいれば、兄弟姉妹は次の職場になります.
兄弟姉妹がいない場合は、ルートに戻るまで親に表示されます.
5. Render and Commit
現在のコードでは、新しいノードがDOMに追加されると、ブラウザはレンダリングツリーが完了する前に操作を停止できます.この場合、未完了のUIが表示されます.
このため,DOMの論理を削除するのではなく,ファイバルーティングを追跡する.これをwipRoot(work in progress rot)と呼びます.
すべての作業が完了すると(次の作業がない場合)、繊維ツリー全体がドームにコミットされます.
この処理はcommitRoot関数で行います.ここでは、domにすべてのノードを再帰的に追加します.
6.回復(再調整)
Nodeのupdateとdeleteはrender関数を用いて得られたelementを最後にコミットされたfiberツリーと比較する.
このため、提出後に最後の繊維樹を保存します.これを現在のルートと呼びます.
その後、すべての繊維特性にalternateを追加します.これは以前の段階で提出された繊維です.
次いで、performUnitOfWorkから新しい繊維を生成する論理を抽出し、reconcileChildren
関数を生成する.従来の繊維の子供と再調整が必要な元素を比較するために、同時に巡回する.
ElementとoldFiberのtype
の比較
Nodeのupdateとdeleteはrender関数を用いて得られたelementを最後にコミットされたfiberツリーと比較する.
このため、提出後に最後の繊維樹を保存します.これを現在のルートと呼びます.
その後、すべての繊維特性にalternateを追加します.これは以前の段階で提出された繊維です.
次いで、performUnitOfWorkから新しい繊維を生成する論理を抽出し、
reconcileChildren
関数を生成する.従来の繊維の子供と再調整が必要な元素を比較するために、同時に巡回する.ElementとoldFiberの
type
の比較effectTag
プロパティを追加します.削除するノードを追跡する代理配列を作成します.
commitRootでdelegation配列を巡回してcommitWorkを実行します.commitWork関数では、effectTag追加、removeChildまたはupdateを使用します.
更新のために
updateDom
関数を作成します.従来の繊維の支柱と新繊維の支柱とを比較し,消失した支柱を取り除き,異なる支柱を設けた.onで始まるprops(event)がある場合はeventListenerを追加します.
7.関数構成部品
関数型素子から作製したファイバはDOMノードを持たない.だから子供たちを道具に持ち込むのではなく、関数を呼び出します.
繊維タイプが関数であるかどうかを確認した後、updateFunctionComponent
に変更してこれまでと同じ役割を果たした.
8. Hook
関数構成部品にステータスを追加します.const Myact = {
createElement,
render,
useState,
}
/** @jsx Didact.createElement */
function Counter() {
const [state, setState] = Didact.useState(1)
return (
<h1 onClick={() => setState(c => c + 1)}>
Count: {state}
</h1>
)
}
const element = <Counter />
const container = document.getElementById("root")
Didact.render(element, container)
let wipFiber = null
let hookIndex = null
function updateFunctionComponent(fiber) {
wipFiber = fiber
hookIndex = 0
wipFiber.hooks = []
const children = [fiber.type(fiber.props)]
reconcileChildren(fiber, children)
}
関数型構成部品を呼び出す前に useState
関数の内部で使用するためにグローバル変数を初期化する必要があります.
まず作業中の繊維を設定します.さらに,このファイバはhook 배열
を追加し,同じ素子がusState関数を複数回呼び出すことを可能にした.function useState(initial) {
const oldHook =
wipFiber.alternate &&
wipFiber.alternate.hooks &&
wipFiber.alternate.hooks[hookIndex]
const hook = {
state: oldHook ? oldHook.state : initial,
}
wipFiber.hooks.push(hook)
hookIndex++
return [hook.state]
}
関数型構成部品がuserStateを呼び出すと、古いhookであるかどうかを確認し、hookインデックスを使用してファイバのalternateを確認します.
古いhookを持っている場合、初期化ステータスがない場合は、このhookのステータスを新しいhookにコピーします.
その後、新しいHookをファイバに追加し、Hookインデックス値を増やしてstateに戻ります.const hook = {
state: oldHook ? oldHook.state : initial,
queue: [],
}
const setState = action => {
hook.queue.push(action)
wipRoot = {
dom: currentRoot.dom,
props: currentRoot.props,
alternate: currentRoot,
}
nextUnitOfWork = wipRoot
deletions = []
}
wipFiber.hooks.push(hook)
hookIndex++
return [hook.state, setState]
}
また、userStateは、更新状態の関数も返さなければならないため、動作を受信するsetState関数も定義します.このアクションをHookに追加するヒントに追加します
次に、レンダー関数と同様の操作を行い、新しいwipルートを次の単位に設定して、繰り返し文で新しいレンダーステップを開始します.const actions = oldHook ? oldHook.queue : []
actions.forEach(action => {
hook.state = action(hook.state)
})
まだアクションが実行されていません.これは、素子レンダリング後に実行され、古いHookのキューからすべてのアクションが取得され、新しいHook stateに適用され、更新されたstateが取得されます.
新知
関数構成部品にステータスを追加します.
const Myact = {
createElement,
render,
useState,
}
/** @jsx Didact.createElement */
function Counter() {
const [state, setState] = Didact.useState(1)
return (
<h1 onClick={() => setState(c => c + 1)}>
Count: {state}
</h1>
)
}
const element = <Counter />
const container = document.getElementById("root")
Didact.render(element, container)
let wipFiber = null
let hookIndex = null
function updateFunctionComponent(fiber) {
wipFiber = fiber
hookIndex = 0
wipFiber.hooks = []
const children = [fiber.type(fiber.props)]
reconcileChildren(fiber, children)
}
関数型構成部品を呼び出す前に useState
関数の内部で使用するためにグローバル変数を初期化する必要があります.まず作業中の繊維を設定します.さらに,このファイバは
hook 배열
を追加し,同じ素子がusState関数を複数回呼び出すことを可能にした.function useState(initial) {
const oldHook =
wipFiber.alternate &&
wipFiber.alternate.hooks &&
wipFiber.alternate.hooks[hookIndex]
const hook = {
state: oldHook ? oldHook.state : initial,
}
wipFiber.hooks.push(hook)
hookIndex++
return [hook.state]
}
関数型構成部品がuserStateを呼び出すと、古いhookであるかどうかを確認し、hookインデックスを使用してファイバのalternateを確認します.古いhookを持っている場合、初期化ステータスがない場合は、このhookのステータスを新しいhookにコピーします.
その後、新しいHookをファイバに追加し、Hookインデックス値を増やしてstateに戻ります.
const hook = {
state: oldHook ? oldHook.state : initial,
queue: [],
}
const setState = action => {
hook.queue.push(action)
wipRoot = {
dom: currentRoot.dom,
props: currentRoot.props,
alternate: currentRoot,
}
nextUnitOfWork = wipRoot
deletions = []
}
wipFiber.hooks.push(hook)
hookIndex++
return [hook.state, setState]
}
また、userStateは、更新状態の関数も返さなければならないため、動作を受信するsetState関数も定義します.このアクションをHookに追加するヒントに追加します次に、レンダー関数と同様の操作を行い、新しいwipルートを次の単位に設定して、繰り返し文で新しいレンダーステップを開始します.
const actions = oldHook ? oldHook.queue : []
actions.forEach(action => {
hook.state = action(hook.state)
})
まだアクションが実行されていません.これは、素子レンダリング後に実行され、古いHookのキューからすべてのアクションが取得され、新しいHook stateに適用され、更新されたstateが取得されます.新知
Reference
この問題について(独自のライブラリを作成), 我々は、より多くの情報をここで見つけました https://velog.io/@ouo_yoonk/나만의-리액트-라이브러리를-만들어보자-gjmokobrテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol