Skip to content

Commit 258f2da

Browse files
authored
FY-215/feature context refactoring (#37)
* FY-215/perf(changedBits): remove changedBits 삭제 facebook/react#20953 * FY-215/refactor: remove threadcount * FY-215/refactor: remove rendererSigil * FY-215/refactor: project * FY-215/refactor: remain observedBits
1 parent b3d4f78 commit 258f2da

22 files changed

+42
-134
lines changed

srcs/context/constructor/context.js

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,16 @@
66
/**
77
*
88
* @param {Symbol} $$typeof
9-
* @param {Function} _calculateChangedBits
109
* @param {any} _currentValue
1110
* @param {any} _currentValue2
12-
* @param {Number} _threadCount
1311
* @param {TProvider} Provider
1412
* @param {TConsumer} Consumer
1513
*/
1614
const context = class {
17-
constructor($$typeof, _calculateChangedBits, _currentValue, _currentValue2, _threadCount, Provider, Consumer) {
15+
constructor($$typeof, _currentValue, _currentValue2, Provider, Consumer) {
1816
this.$$typeof = $$typeof;
19-
this._calculateChangedBits = _calculateChangedBits;
2017
this._currentValue = _currentValue;
2118
this._currentValue2 = _currentValue2;
22-
this._threadCount = _threadCount;
2319
this.Provider = Provider;
2420
this.Consumer = Consumer;
2521
}
@@ -28,23 +24,13 @@ const context = class {
2824
/**
2925
*
3026
* @param {Symbol} $$typeof
31-
* @param {Function} _calculateChangedBits
3227
* @param {any} _currentValue
3328
* @param {any} _currentValue2
34-
* @param {Number} _threadCount
3529
* @param {TProvider} Provider
3630
* @param {TConsumer} Consumer
3731
*/
38-
const createContextInst = (
39-
$$typeof,
40-
calculateChangedBits,
41-
currentValue,
42-
currentValue2,
43-
threadCount,
44-
Provider,
45-
Consumer
46-
) => {
47-
return new context($$typeof, calculateChangedBits, currentValue, currentValue2, threadCount, Provider, Consumer);
32+
const createContextInst = ($$typeof, currentValue, currentValue2, threadCount, Provider, Consumer) => {
33+
return new context($$typeof, currentValue, currentValue2, threadCount, Provider, Consumer);
4834
};
4935

5036
export default createContextInst;

srcs/context/constructor/contextItem.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,22 @@
66
/**
77
*
88
* @param {TContext} context
9-
* @param {number} observedBits
109
* @param {import("../../../type/TContextItem").TContextItem | null} next
1110
*/
1211
const contextItem = class {
13-
constructor(context, observedBits, next) {
12+
constructor(context, next) {
1413
this.context = context;
15-
this.observedBits = observedBits;
1614
this.next = next;
1715
}
1816
};
1917

2018
/**
2119
*
2220
* @param {TContext} context
23-
* @param {number} observedBits
24-
* @param {import("../../../type/TContextItem").TContextItem | null} next
21+
* @param {number, * @param {import("../../../type/TContextItem").TContextItem | null}} next
2522
*/
26-
const createContextItem = (context, observedBits, next) => {
27-
return new contextItem(context, observedBits, next);
23+
const createContextItem = (context, next) => {
24+
return new contextItem(context, next);
2825
};
2926

3027
export default createContextItem;

srcs/context/core/contextCore.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@ import { createCursor } from "../../fiber/fiberStack.js";
44
* @property {Cursor} valueCursor - fiberStack을 가리키고 있으며, 현재 context의 value를 가리킨다.
55
* @property {undefined | string} rendererSigil - 해당 변수는 여러개의 renderer가 동시에 동작할 때,
66
* 같은 context를 공유하는지 확인하기 위한 변수이다. 현재 react 16.12.0은 해당기능을 지원하지 않기 때문에
7-
* 개발 모드에서 warning을 출력하기 위해 사용된다.
7+
* 개발 모드에서 warning을 출력하기 위해 사용된다. -> NOTE: 사용하지 않음
88
* @property {Fiber | null} currentlyRenderingFiber - 현재 렌더링 중인 fiber를 가리킨다.
99
* @property {TContextItem | null} lastContextDependency - 마지막으로 의존성을 가진 contextItem를 가리킨다.
10-
* @property {TContext | null} lastContextWithAllBitsObserved - 마지막으로 모든 bit를 관찰한 context를 가리킨다.
10+
* @property {TContext | null} lastFullyObservedContext - 마지막으로 완전히 관찰된 context를 가리킨다.
1111
*/
1212
export default {
1313
valueCursor: createCursor(null),
14-
rendererSigil: undefined,
1514
currentlyRenderingFiber: null,
1615
lastContextDependency: null,
17-
lastContextWithAllBitsObserved: null,
16+
lastFullyObservedContext: null,
1817
};

srcs/context/createContext.js

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,17 @@ import createProvider from "./constructor/provider.js";
55
/**
66
*
77
* @param {any} defaultValue
8-
* @param {Function | undefined} calculateChangedBits
98
* @see ReactNewContext-test.internal.js 1055 line
109
*
1110
* @description - 단순히 context 객체를 생성하는 함수입니다. 그 과정에서
1211
* Provider와 Consumer를 생성합니다.
1312
*
14-
* @description - calculateChangedBits
15-
* 비트 마스킹을 사용하여 변경되었다면 Context.consumer를 re-render합니다. 그것을
16-
* 클라이언트 코드에서 조정할 수 있도록 직접 second argument로 넘겨줄 수 있습니다.
17-
* 관련 링크는 아래에 있습니다.
1813
* @link https://dev.to/alexkhismatulin/react-context-a-hidden-power-3h8j
1914
* @returns
2015
*/
21-
const createContext = (defaultValue, calculateChangedBits) => {
22-
// client Code에서 calculateChangedBits를 넘겨주지 않았다면 null을 할당합니다.
23-
if (calculateChangedBits === undefined) {
24-
calculateChangedBits = null;
25-
}
26-
16+
const createContext = (defaultValue) => {
2717
// context Object를 생성합니다.
28-
const context = createContextInst(
29-
RFS_CONTEXT_TYPE,
30-
calculateChangedBits,
31-
defaultValue,
32-
defaultValue,
33-
0,
34-
null,
35-
null
36-
);
18+
const context = createContextInst(RFS_CONTEXT_TYPE, defaultValue, defaultValue, null, null);
3719

3820
// Provider 객체 생성.
3921
const provider = createProvider(RFS_PROVIDER_TYPE, context);

srcs/context/newContext.js

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { MAX_SIGNED_31_BIT_INT } from "../const/CExpirationTime.js";
21
import { pop, push } from "../fiber/fiberStack.js";
32
import { markWorkInProgressReceivedUpdate } from "../work/beginWork.js";
43
import createContextItem from "./constructor/contextItem.js";
54
import contextCore from "./core/contextCore.js";
65
// TODO: import { isPrimaryRenderer } from "react-dom";
7-
// ReactDOMHostConfig에서 isPrimaryRenderer를 가져옵니다.
6+
// RFS의 ReactDOMHostConfig에서 isPrimaryRenderer를 가져옵니다.
87

98
/**
109
*
@@ -25,12 +24,10 @@ const pushProvider = (providerFiber, nextValue) => {
2524
push(contextCore.valueCursor, context._currentValue, providerFiber);
2625

2726
context._currentValue = nextValue;
28-
context._currentRenderer = contextCore.rendererSigil;
2927
} else {
3028
push(contextCore.valueCursor, context._currentValue2, providerFiber);
3129

3230
context._currentValue2 = nextValue;
33-
context._currentRenderer2 = contextCore.rendererSigil;
3431
}
3532
};
3633

@@ -102,7 +99,7 @@ const scheduleWorkOnParentPath = (parent, renderExpirationTime) => {
10299
* // 이때 변경되었다는 것을 알리는 용도로 해당 fiber의 expirationTime을 변경합니다.
103100
* @returns
104101
*/
105-
const propagateContextChange = (workInProgress, context, changedBits, renderExpirationTime) => {
102+
const propagateContextChange = (workInProgress, context, renderExpirationTime) => {
106103
let fiber = workInProgress.child;
107104
if (fiber !== null) {
108105
// Set the return pointer of the child to the work-in-progress fiber.
@@ -122,14 +119,9 @@ const propagateContextChange = (workInProgress, context, changedBits, renderExpi
122119
// Check if the context matches.
123120
// 현재 fiber의 context list중에서 현재 변경된 context와 일치하는 context가 있는지 확인합니다.
124121
// 만약에 일치하면서 변경되었다면 해당 fiber를 re-render해야합니다.
125-
if (dependency.context === context && (dependency.observedBits & changedBits) !== 0) {
122+
if (dependency.context === context) {
126123
// Match! Schedule an update on this fiber.
127124

128-
if (fiber.tag === ClassComponent) {
129-
// NOTE: we don't implement ClassComponent.
130-
// 저희는 함수형 컴포넌트만 사용하기 때문에 해당 부분은 구현하지 않습니다.
131-
}
132-
133125
// fiber를 re-render하기 때문에 해당 fiber의 expirationTime을 변경합니다.
134126
if (fiber.expirationTime < renderExpirationTime) {
135127
fiber.expirationTime = renderExpirationTime;
@@ -161,12 +153,10 @@ const propagateContextChange = (workInProgress, context, changedBits, renderExpi
161153
} else if (fiber.tag === ContextProvider) {
162154
// Don't scan deeper if this is a matching provider
163155
nextFiber = fiber.type === workInProgress.type ? null : fiber.child;
164-
} else if (fiber.tag === DehydreatedFragment) {
165-
// NOTE: we don't implement DehydreatedFragment.
166-
// it's server components
167156
} else {
168157
nextFiber = fiber.child;
169158
}
159+
// NOTE: we don't implement DehydreatedFragment.
170160

171161
// nextFier가 null이라는 것은 더이상 child가 없다는 것.
172162
// 그러면 sibling을 확인하고 그마저도 존재하지 않는다면 parent로 올라갑니다.
@@ -210,7 +200,7 @@ const propagateContextChange = (workInProgress, context, changedBits, renderExpi
210200
const prepareToReadContext = (workInProgress, renderExpirationTime) => {
211201
contextCore.currentlyRenderingFiber = workInProgress;
212202
contextCore.lastContextDependency = null;
213-
contextCore.lastContextWithAllBitsObserved = null;
203+
contextCore.lastFullyObservedContext = null;
214204

215205
// component는 여러개의 context를 사용할 수 있습니다.
216206
// dependencies는 해당 fiber에서 사용되는 컨텍스트의 리스트입니다.
@@ -234,27 +224,16 @@ const prepareToReadContext = (workInProgress, renderExpirationTime) => {
234224
/**
235225
*
236226
* @param {Tcontext} context
237-
* @param {number} observedBits
238227
*
239228
* @description - readContext의 목표는 context 값을 읽는 것입니다.
240229
* 이 함수에서 context의 값을 읽습니다.
241230
* @returns
242231
*/
243-
const readContext = (context, observedBits) => {
244-
if (contextCore.lastContextWithAllBitsObserved === context) {
232+
const readContext = (context) => {
233+
if (contextCore.lastFullyObservedContext === context) {
245234
// Nothing to do. We already observe everything in this context.
246-
} else if (observedBits === false || observedBits === 0) {
247-
// Do not observe any updates.
248235
} else {
249-
let resolvedObservedBits;
250-
if (typeof observedBits !== "number" || observedBits === MAX_SIGNED_31_BIT_INT) {
251-
contextCore.lastContextWithAllBitsObserved = context;
252-
resolvedObservedBits = MAX_SIGNED_31_BIT_INT;
253-
} else {
254-
resolvedObservedBits = observedBits;
255-
}
256-
257-
const contextItem = createContextItem(context, resolvedObservedBits, null);
236+
const contextItem = createContextItem(context, null);
258237

259238
if (contextCore.lastContextDependency === null) {
260239
// this is the first dependency for this component. Create a new list.

srcs/core/UpdateQueue.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import { UpdateState } from "../const/CUpdateTag.js";
3434
import { NoWork } from "../const/CExpirationTime.js";
3535
import { markUnprocessedUpdateTime, markRenderEventTimeAndConfig } from "../work/workloop.js";
3636
import { Callback } from "../const/CSideEffectFlags.js";
37-
import { TFiber } from "../../type/TFiber.js";
3837

3938
export class updateState {
4039
/**

srcs/fiber/childFiber.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import { isArray } from "../shared/isArray.js";
1+
import isArray from "../shared/isArray.js";
22
import { RFS_ELEMENT_TYPE, RFS_FRAGMENT_TYPE } from "../core/rfsSymbol.js";
33
import { createWorkInProgress } from "../fiber/fiber.js";
44
import { getIteratorFn } from "../core/rfsSymbol.js";
5-
import { TFiber } from "../../type/TFiber.js";
65
import { createFiberFromElement, createFiberFromFragment, createFiberFromText } from "../fiber/fiber.js";
76
//Reconcile
87
//하나의 트리를 가지고 다른 트리로 변환하기 위한 최소한의 연산 수를 구하는 알고리즘 문제를 풀기 위한 일반적인 해결책들이 있습니다.
@@ -552,8 +551,8 @@ const ChildReconciler = (shouldTrackSideEffects) => {
552551
//그리고 마지막으로 배치가 바뀌지 않은 파이버의 인덱스를 가르키는 변수를 업데이트해야됨
553552
//NOTE: place-배치란 list에서의 배치를 의미함-> 이것은 array에서 index를 바꾸는 것이
554553
//NOTE:아닌 인접한것을 기준을 의미함 (fiber 자체가 list구조이므로)
555-
//NOTE: placeChild의 알고리즘은 placeChild를 참고하면
556-
554+
//NOTE: placeChild의 알고리즘은 placeChild를 참고하면
555+
557556
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
558557

559558
//딱 한번만 resultFirstFiber를 세팅해야됨

srcs/hooks/core/renderWithHooks.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ const finishRenderingHooks = (hookCore, hookExpirationTime) => {
2727
hookCore.sideEffectTag = 0;
2828

2929
// finish hookExpirationTime
30-
// TODO: import NoWork
3130
hookExpirationTime.renderExpirationTime = NoWork;
3231
hookExpirationTime.remainingExpirationTime = NoWork;
3332
};
@@ -55,7 +54,7 @@ const renderWithHooks = (current, workInProgress, Component, props, refOrContext
5554
}
5655

5756
// Component render
58-
// TODO: ?? 그러면 props랑 context랑 같이 들어오는데? 이게 뭐지.
57+
// NOTE: refOrContext를 넣어주는 이유는 ClassComponent 때문.
5958
let children = Component(props, refOrContext);
6059

6160
// render phase시에 update가 발생했다면 해당 Component를 다시 렌더링합니다.

srcs/hooks/shared/dispatchAction.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { NoWork } from "../../const/CExpirationTime.js";
22
import is from "../../shared/objectIs.js";
3+
import { computeExpirationForFiber, requestCurrentTimeForUpdate, scheduleWork } from "../../work/workloop.js";
34
import createHookUpdate from "../constructor/hookUpdate.js";
45
import hookCore from "../core/hookCore.js";
56
import hookExpirationTime from "../core/hookExpirationTime.js";
6-
import hookRenderPhase from "../core/hookRenderPhase.js";
7+
import hookRenderPhase, { RE_RENDER_LIMIT } from "../core/hookRenderPhase.js";
78
import enqueueRenderPhaseUpdate from "./enqueueRenderPhaseUpdate.js";
89

910
/**
@@ -26,6 +27,10 @@ import enqueueRenderPhaseUpdate from "./enqueueRenderPhaseUpdate.js";
2627
*/
2728

2829
const dispatchAction = (fiber, queue, action) => {
30+
if (hookRenderPhase.numberOfReRenders < RE_RENDER_LIMIT) {
31+
throw new Error("Too many re-renders. React limits the number of renders to prevent an infinite loop.");
32+
}
33+
2934
const alternate = fiber.alternate;
3035

3136
// TODO: isRenderPhaseUpdate 함수로 Refactor
@@ -64,14 +69,9 @@ const dispatchAction = (fiber, queue, action) => {
6469
}
6570
} else {
6671
// this is an idle status update
67-
68-
// TODO: Implement this function. requestCurrentTimeForUpdate
6972
const currentTime = requestCurrentTimeForUpdate();
70-
// TODO: Implement this function. requestCurrentSuspenseConfig 사용하지 않을 수 있음
71-
const suspenseConfig = requestCurrentSuspenseConfig();
72-
// TODO: Implement this function. computeExpirationForFiber
7373
// hookupdate에서 suspenseConfig를 사용하고 있는데 이후 updateReducer의 markRenderEventTimeAndConfig에서만 사용된다
74-
const expirationTime = computeExpirationForFiber(currentTime, fiber, suspenseConfig);
74+
const expirationTime = computeExpirationForFiber(currentTime, fiber);
7575

7676
const update = createHookUpdate(expirationTime, suspenseConfig, action, null, null, null);
7777
enqueueRenderPhaseUpdate(queue, update);
@@ -94,7 +94,7 @@ const dispatchAction = (fiber, queue, action) => {
9494
// The queue is currently empty, which means we can eagerly compute the
9595
// next state before entering the render phase. If the new state is the
9696
// same as the current state, we may be able to bail out entirely.
97-
//NOTE:여기서의 Bailout은 scheduleWork를 호출하지 않는다는 것인듯.
97+
//NOTE: 여기서의 Bailout은 scheduleWork를 호출하지 않는다는 것인듯.
9898
const lastRenderedReducer = queue.lastRenderedReducer;
9999
if (lastRenderedReducer !== null) {
100100
try {
@@ -113,7 +113,6 @@ const dispatchAction = (fiber, queue, action) => {
113113
}
114114
}
115115
}
116-
// TODO: Implement this function. scheduleWork
117116
scheduleWork(fiber, expirationTime);
118117
}
119118
};

0 commit comments

Comments
 (0)