/images/art2.png

Understanding React Fiber - Trees, Diff, and Commit Phases

Introduction

React Fiber is the core of modern React rendering, enabling incremental rendering, time slicing, and high-performance updates. In this blog, we will explore:

  • Fiber nodes and structure
  • Fiber loop and traversal
  • Diff/reconciliation algorithm
  • Work-in-progress (WIP) tree
  • Current fiber tree vs real DOM
  • Commit phase and tree flow

1. What is a Fiber Node?

A Fiber node is a unit of work in React’s incremental rendering. It contains:

  • type → element type (div, span, Component)
  • key → unique identifier for list reconciliation
  • props → element properties
  • stateNode → reference to actual DOM node or component instance
  • child, sibling, return → pointers for tree traversal
  • alternate → link to the previous fiber (used for diffing)
  • effectTag → indicates updates needed (Placement, Update, Deletion)

Example fiber node:

React Concurrent

What is React Concurrent?

“Concurrent Features” is a set of rendering capabilities introduced to make React apps more responsive. Instead of blocking the browser until all rendering is done, React can pause, resume, and even abandon a render in progress.

This allows React to:

  • Prioritize urgent updates (e.g., typing) over non-urgent ones (e.g., background data fetch results)
  • Avoid dropping frames during animations or scrolling
  • Keep the UI feeling “alive” even when there’s a lot of work to do

The underlying mechanism is cooperative scheduling — React voluntarily yields control back to the browser when time is up, and continues work later.

Asynchronous in JS

Synchronous & asynchronous

Function run synchronously means code is running as same as your writing.

But in real situation, some code may need time to running (like fetch). If synchronously run all code, program will be block and wait this time consuming part finish and continue.

In the most of the time, You code logic need wait to continue but you don’t want to block all progress. Maybe UI rendering or some other total unrelated code. Unfortunately, JS is single thread langrage and concurrency is not exist. Therefore, you need some technique to some part running asynchronously,

HTML/Document Trick

Understanding offsetWidth, clientWidth, scrollWidth

Note
All these property will round the value to an integer. If you need a fractional value, use element.getBoundingClientRect().

Get Scrollbar width

Reference: https://www.30secondsofcode.org/js/s/get-scrollbar-width/

Get window scroll bar width

const getScrollbarWidth = () =>
    window.innerWidth - document.documentElement.clientWidth;

getScrollbarWidth();

Get a element scroll bar width

const getScrollbarWidth = (el) => {
    const leftBorder = parseInt(
        getComputedStyle(el).getPropertyValue('border-left-width'),
        10
    );
    const rightBorder = parseInt(
        getComputedStyle(el).getPropertyValue('border-right-width'),
        10
    );

    return el.offsetWidth - el.clientWidth - leftBorder - rightBorder;
};

getScrollbarWidth(el);

Element: getBoundingClientRect()

el.getBoundingClientRect() will return: left, top, right, bottom, x, y, width, and height.

Typescript Trick

generic types optional

To make a generic type optional, you have to assign the void as the default value.

const fetchData = <T = void>(url: string): T => {
    const res: T = fetch(url);
    return res;
};

https://garbagevalue.com/blog/optional-generic-typescript#quick-solutions-make-generic-type-optional

string[ ] & [ string, …string[ ] ]

The main difference is that type [string, ...string[]] at least have one element. [] will alert error. string[] could be empty. [] is ok.

Test markdown

Contents

Introduction

This is a test blog post written in Markdown. It demonstrates common features used in blog writing.

test

header 2

header 3

header 4

header 5

list

normal list

  • Easy to write
  • Supports formatting
  • Clean and readable
  • Works with most static site generators

order list

  1. 123123
  2. asdfadsf
  3. lkasdf

Code Example

// Simple JavaScript function
function greet(name) {
  return `Hello, ${name}!`;
}

Features

Clean formatting Blockquotes for every section Inline links like OpenAI Quoted links: 👉 Visit Example Site

ffmpeg

Reference

official

https://ffmpeg.org

blog

https://fireship.io/lessons/ffmpeg-useful-techniques/

node js

https://www.npmjs.com/package/fluent-ffmpeg

example

concatenate

ffmpeg -f concat -i vids.txt -c copy out.mp4

vids.txt:

file 'name1.mov'
file 'name2.mov'
file 'name3.mov'

Type convention

ffmpeg -i in.mp4 out.mov

ffmpeg -i in.mp4 out.gif

Scale

It very common to reduce size of output file. Change scale usually the common and efficient way to do so.

Design Pattern

Design pattern

Factory pattern

const createDataBaseClass = (dbName: DBOption) => {
    switch (dbName) {
        case 'InMemo':
            return InMemoryDataBase;
        case 'SQL':
            return SQL_DB;

        // ...
        // you can add anything else
        default:
            break;
    }
};

Singleton pattern

export const createDataBase = <T extends BaseRecord>() => {
    const db = new InMemoryDataBase<T>();
    return db;
};

const pokemonDB = createDataBase<Pokemon>();

pokemonDB.set({
    id: 'Bulbasaur',
    attack: 59,
    defense: 10,
});

console.log(pokemonDB.get('Bulbasaur'));

// A CPP way to do
const createDataBase2 = <T extends BaseRecord>() => {
    class InMemoryDataBase2 implements DataBase<T> {
        private db: Record<string, T> = {};
        static instance: InMemoryDataBase2 = new InMemoryDataBase2();

        private constructor() {} // private constructor is necessary

        public set(newValue: T): void {
            this.db[newValue.id] = newValue;
        }

        public get(id: string): T | undefined {
            return this.db[id];
        }
    }

    return InMemoryDataBase2;
};
const PokemonDB2 = createDataBase2<Pokemon>();
PokemonDB2.instance.set({
    id: 'Bulbasaur',
    attack: 59,
    defense: 10,
});

Observer (pub/sub) pattern

// ++++++++++  Observer  ++++++++++
const createObserver = <EventType>(): {
    subscribe: (listener: listenerType<EventType>) => () => void; // take listener and return an unsubscribe function
    publish: (event: EventType) => void;
} => {
    let listeners: listenerType<EventType>[] = [];
    return {
        subscribe: (listener: listenerType<EventType>): (() => void) => {
            listeners.push(listener);
            return () => {
                listeners = listeners.filter((l) => l !== listener);
            };
        },
        publish: (event: EventType) => {
            listeners.forEach((l) => l(event));
        },
    };
};

//  +++++++++++++++++++++++++++++

interface BeforeAddValueEvent<T> {
    newValue: T;
    value: T;
}
interface AfterAddValueEvent<T> {
    value: T;
}

class InMemoryDBWithObserver<T extends BaseRecord> extends InMemoryDataBase<T> {
    public set(newValue: T): void {
        this.BeforeAddValueObserver.publish({
            newValue,
            value: this.db[newValue.id],
        });
        this.db[newValue.id] = newValue;
        this.AfterAddValueObserver.publish({
            value: newValue,
        });
    }

    public get(id: string): T | undefined {
        return this.db[id];
    }
    // observer
    private BeforeAddValueObserver = createObserver<BeforeAddValueEvent<T>>();
    private AfterAddValueObserver = createObserver<AfterAddValueEvent<T>>();

    onBeforeAddValue(
        listener: listenerType<BeforeAddValueEvent<T>>
    ): () => void {
        return this.BeforeAddValueObserver.subscribe(listener);
    }

    onAfterAddValue(listener: listenerType<AfterAddValueEvent<T>>): () => void {
        return this.AfterAddValueObserver.subscribe(listener);
    }

    // visiter pattern
    visit(visitor: (item: T) => void): void {
        Object.values(this.db).forEach(visitor);
    }

    // strategy pattern
    getBest(strategy: (item: T) => number): T {
        let findRes: { max: number; res: T | null } = {
            max: -Infinity,
            res: null,
        };

        return Object.values(this.db).reduce((prev, cur) => {
            let score = strategy(cur);
            if (prev.max < score) return { max: score, res: cur };
            return prev;
        }, findRes).res;
    }
}

const pokemonDB = new InMemoryDBWithObserver<Pokemon>();

pokemonDB.onBeforeAddValue((event) => {
    console.log('Before add value');
    console.log(event);
});

const unsubscribe = pokemonDB.onAfterAddValue((event) => {
    console.log('After ADD A Value');
    console.log(event);
});
pokemonDB.onAfterAddValue((event) => {
    console.log('-----------');
});

pokemonDB.set({
    id: 'Bulbasaur',
    attack: 59,
    defense: 10,
});
pokemonDB.set({
    id: 'Bulbasaur',
    attack: 20,
    defense: 30,
});

unsubscribe();

pokemonDB.set({
    id: 'Spinpsaur',
    attack: 159,
    defense: 110,
});

console.log('Visit pattern:');
pokemonDB.visit((item) => console.log(item));

console.log('strategy pattern:');
console.log(pokemonDB.getBest((item) => item.defense));

Adaptor pattern

Typescript overview

type

Union type & Literal type

const add = (
    a: number | string,
    b: number | string,
    type?: 'number' | 'string'
): number | string => {
    if (type === 'string') {
        return a.toString() + b.toString();
    } else return +a + +b;
};

console.log(add(1, 2));

Array

type Book = {
    id: string;
    name: string;
};

let books: Book[] = [];

unknown

let test1: unknown;
let test2: string;

test1 = 'xyz'; // ok
// test2 = test1; // error
function f1(a: any) {
    a.b(); // OK
}
function f2(a: unknown) {
    a.b(); //error
    // Object is of type 'unknown'.
}

Type a Function

type listenerType<EventType> = (event: EventType) => void;

Assign a plain Object

type Primitive = bigint | boolean | null | number | string | symbol | undefined;

type PlainObject = Record<string, Primitive>;
const obj1: PlainObject = { a: 1 }; //✅
const obj2: PlainObject = { a: 1 }; //❌
const obj3: PlainObject = new myClass(); //❌

Assign a nested plain Object

type Primitive = bigint | boolean | null | number | string | symbol | undefined;

type JSONValue = Primitive | JSONObject | JSONArray;
interface JSONObject {
    [key: string]: JSONValue;
}
interface JSONArray extends Array<JSONValue> {}

const obj1: PlainObject = { a: 1 }; //✅
const obj2: PlainObject = { a: { b: { c: 3 } } }; //✅
const obj3: PlainObject = new myClass(); //❌

Type Template arrow function example

export const useFetchAPI = <T extends unknown>(
    url: string,
    method: 'POST' | 'GET',
    body?: string | JSONObject
): [string, T | null] => {
    const [fetchStatus, setFetchStatus] = useState('error');
    const [fetchResult, setFetchResult] = useState<T | null>(null);

    useEffect(() => {
        const apiMockFetch: () => Promise<{
            status: string;
            requestId: string;
            result: T | null;
        }> = () => {
            return new Promise((resolve) => {
                setTimeout(() => {
                    resolve(someData);
                }, 1000);
            });
        };

        const fetchData = async () => {
            const { status, result } = await apiMockFetch();
            setFetchStatus(status);
            if (result !== undefined) {
                setFetchResult(result);
            }
        };
        if (fetchStatus !== 'success') fetchData();
    }, [url, method, body, fetchStatus]);
    return [fetchStatus, fetchResult];
};

Type & interface

type Book = {
    id: string;
    name: string;
};

interface Book {
    id: string;
    name: string;
}

React Logic Reuse Example

React logic extraction

Check this post

Example code

This example demonstrate one single feature using four different feature to archive code split

Code running there: –>Link<–

import { useState, useEffect } from React;

const Styles = {
    redBorder: {
        border: '1px solid #f00',
    },
};

const MouseDisplay = ({ x, y }) => {
    return (
        <div>
            Mouse at x: {x} ; y: {y}
        </div>
    );
};
const MouseDisplay2 = ({ x, y }) => {
    return (
        <div style={{ color: 'teal' }}>
            Mouse at x: {x} ; y: {y}
        </div>
    );
};

// Normal
export const MouseInfoAndDisplay = () => {
    const [x, setX] = useState(0);
    const [y, setY] = useState(0);
    const handleMove = (e) => {
        setX(e.clientX);
        setY(e.clientY);
    };
    return (
        <div style={Styles.redBorder} onMouseMove={handleMove}>
            <MouseDisplay x={x} y={y} />
        </div>
    );
};

// HOC
const withMouseInfo = (Component) => {
    return (props) => {
        const [x, setX] = useState(0);
        const [y, setY] = useState(0);
        const handleMove = (e) => {
            setX(e.clientX);
            setY(e.clientY);
        };
        return (
            <div style={Styles.redBorder} onMouseMove={handleMove}>
                <Component {...props} x={x} y={y} />
            </div>
        );
    };
};

export const HOCMouseDisplay = withMouseInfo(MouseDisplay);
export const HOCMouseDisplay2 = withMouseInfo(MouseDisplay2);

// Render Props

const MouseRenderProps = ({ render }) => {
    const [x, setX] = useState(0);
    const [y, setY] = useState(0);
    const handleMove = (e) => {
        setX(e.clientX);
        setY(e.clientY);
    };

    return (
        <div style={Styles.redBorder} onMouseMove={handleMove}>
            {render(x, y)}
        </div>
    );
};

export const Mouse = () => {
    return (
        <div>
            <MouseRenderProps render={(x, y) => <MouseDisplay x={x} y={y} />} />
            <MouseRenderProps
                render={(x, y) => <MouseDisplay2 x={x} y={y} />}
            />
        </div>
    );
};

// Customize HOOK

const useMouseState = () => {
    const [x, setX] = useState(0);
    const [y, setY] = useState(0);
    const [node, setNode] = useState(null);
    const handleMove = (e) => {
        setX(e.clientX);
        setY(e.clientY);
    };
    useEffect(() => {
        if (node !== null) {
            node.addEventListener('mousemove', handleMove);
        }
    }, [node]);
    return [x, y, setNode];
};

export const MouseUsingHook = () => {
    const [x1, y1, ref1] = useMouseState();
    const [x2, y2, ref2] = useMouseState();

    return (
        <div>
            <div ref={ref1} style={Styles.redBorder}>
                <MouseDisplay x={x1} y={y1} />
            </div>
            <div ref={ref2} style={Styles.redBorder}>
                <MouseDisplay2 x={x2} y={y2} />
            </div>
        </div>
    );
};


const App = () => {
    return (
        <div
            style={{
                display: 'flex',
                flexDirection: 'column',
                height: '100vh',
                justifyContent: 'space-around',
            }}
        >
            <div>
                Normal: <MouseInfoAndDisplay />
            </div>
            <div>
                HOC: <HOCMouseDisplay /> <HOCMouseDisplay2/>
            </div>
            <div>
                Render Props: <Mouse />
            </div>
            <div>
                Hook: <MouseUsingHook />
            </div>
        </div>
    );
};