2025-04-27 日报 Day169

2025-04-27 日报 Day169

Yuyang 前端小白🥬

今日的鸡汤

铭记誓词、以行践诺。

今日学习内容

1、https://www.youtube.com/watch?v=EVFZazcxAbo

今日笔记

1、JSX的本质:

  • JSX是JavaScript的语法扩展,允许在JavaScript代码中直接编写类似HTML的标签。
  • 在编译(Babel)时,JSX会被转换为React.createElement()调用,这些调用创建了React元素。
  • JSX使得组件的结构更直观,易于理解和维护。
    JSX语法躺允许前端开发者使用最为熟悉的类HTML标签语法来创建虚拟DOM,在降低学习成本的同时,也提升了研发效率和体验。
    USING React Without JSX:
    For example, this code written with JSX:
    1
    2
    3
    4
    5
    6
    7
    8
    class Hello extends React.Component {
    render() {
    return <div>Hello {this.props.toWhat}</div>;
    }
    }

    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(<Hello toWhat="World" />);
    can be rewritten without JSX like this:
    1
    2
    3
    4
    5
    6
    7
    8
    class Hello extends React.Component {
    render() {
    return React.createElement('div', null, `Hello ${this.props.toWhat}`);
    }
    }

    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(React.createElement(Hello, {toWhat: 'World'}, null));

2、createELement源码解析:
https://legacy.reactjs.org/docs/react-api.html#createelement
https://react.dev/reference/react/createElement

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
export function createElement(type, config, children) {
if (__DEV__) {
// We don't warn for invalid element type here because with owner stacks,
// we error in the renderer. The renderer is the only one that knows what
// types are valid for this particular renderer so we let it error there.

// Skip key warning if the type isn't valid since our key validation logic
// doesn't expect a non-string/function type and can throw confusing
// errors. We don't want exception behavior to differ between dev and
// prod. (Rendering will throw with a helpful message and as soon as the
// type is fixed, the key warnings will appear.)
for (let i = 2; i < arguments.length; i++) {
validateChildKeys(arguments[i], type);
}

// Unlike the jsx() runtime, createElement() doesn't warn about key spread.
}

let propName;

// Reserved names are extracted
const props = {};

let key = null;

if (config != null) {
if (__DEV__) {
if (
!didWarnAboutOldJSXRuntime &&
'__self' in config &&
// Do not assume this is the result of an oudated JSX transform if key
// is present, because the modern JSX transform sometimes outputs
// createElement to preserve precedence between a static key and a
// spread key. To avoid false positive warnings, we never warn if
// there's a key.
!('key' in config)
) {
didWarnAboutOldJSXRuntime = true;
console.warn(
'Your app (or one of its dependencies) is using an outdated JSX ' +
'transform. Update to the modern JSX transform for ' +
'faster performance: https://react.dev/link/new-jsx-transform',
);
}
}

if (hasValidKey(config)) {
if (__DEV__) {
checkKeyStringCoercion(config.key);
}
key = '' + config.key;
}

// Remaining properties are added to a new props object
for (propName in config) {
if (
hasOwnProperty.call(config, propName) &&
// Skip over reserved prop names
propName !== 'key' &&
// Even though we don't use these anymore in the runtime, we don't want
// them to appear as props, so in createElement we filter them out.
// We don't have to do this in the jsx() runtime because the jsx()
// transform never passed these as props; it used separate arguments.
propName !== '__self' &&
propName !== '__source'
) {
props[propName] = config[propName];
}
}
}

// Children can be more than one argument, and those are transferred onto
// the newly allocated props object.
const childrenLength = arguments.length - 2;
if (childrenLength === 1) {
props.children = children;
} else if (childrenLength > 1) {
const childArray = Array(childrenLength);
for (let i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
if (__DEV__) {
if (Object.freeze) {
Object.freeze(childArray);
}
}
props.children = childArray;
}

// Resolve default props
if (type && type.defaultProps) {
const defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
if (__DEV__) {
if (key) {
const displayName =
typeof type === 'function'
? type.displayName || type.name || 'Unknown'
: type;
defineKeyPropWarningGetter(props, displayName);
}
}
const trackActualOwner =
__DEV__ &&
ReactSharedInternals.recentlyCreatedOwnerStacks++ < ownerStackLimit;
return ReactElement(
type,
key,
undefined,
undefined,
getOwner(),
props,
__DEV__ &&
(trackActualOwner
? Error('react-stack-top-frame')
: unknownOwnerDebugStack),
__DEV__ &&
(trackActualOwner
? createTask(getTaskName(type))
: unknownOwnerDebugTask),
);
}

CreateElement只是ReactElement的一个包装函数,主要用于处理JSX语法的转换和一些额外的属性处理。
3、ReactElement源码解析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
function ReactElement(
type,
key,
self,
source,
owner,
props,
debugStack,
debugTask,
) {
// Ignore whatever was passed as the ref argument and treat `props.ref` as
// the source of truth. The only thing we use this for is `element.ref`,
// which will log a deprecation warning on access. In the next release, we
// can remove `element.ref` as well as the `ref` argument.
const refProp = props.ref;

// An undefined `element.ref` is coerced to `null` for
// backwards compatibility.
const ref = refProp !== undefined ? refProp : null;

let element;
if (__DEV__) {
// In dev, make `ref` a non-enumerable property with a warning. It's non-
// enumerable so that test matchers and serializers don't access it and
// trigger the warning.
//
// `ref` will be removed from the element completely in a future release.
element = {
// This tag allows us to uniquely identify this as a React Element
$$typeof: REACT_ELEMENT_TYPE,

// Built-in properties that belong on the element
type,
key,

props,

// Record the component responsible for creating this element.
_owner: owner,
};
if (ref !== null) {
Object.defineProperty(element, 'ref', {
enumerable: false,
get: elementRefGetterWithDeprecationWarning,
});
} else {
// Don't warn on access if a ref is not given. This reduces false
// positives in cases where a test serializer uses
// getOwnPropertyDescriptors to compare objects, like Jest does, which is
// a problem because it bypasses non-enumerability.
//
// So unfortunately this will trigger a false positive warning in Jest
// when the diff is printed:
//
// expect(<div ref={ref} />).toEqual(<span ref={ref} />);
//
// A bit sketchy, but this is what we've done for the `props.key` and
// `props.ref` accessors for years, which implies it will be good enough
// for `element.ref`, too. Let's see if anyone complains.
Object.defineProperty(element, 'ref', {
enumerable: false,
value: null,
});
}
} else {
// In prod, `ref` is a regular property and _owner doesn't exist.
element = {
// This tag allows us to uniquely identify this as a React Element
$$typeof: REACT_ELEMENT_TYPE,

// Built-in properties that belong on the element
type,
key,
ref,

props,
};
}

if (__DEV__) {
// The validation flag is currently mutative. We put it on
// an external backing store so that we can freeze the whole object.
// This can be replaced with a WeakMap once they are implemented in
// commonly used development environments.
element._store = {};

// To make comparing ReactElements easier for testing purposes, we make
// the validation flag non-enumerable (where possible, which should
// include every environment we run tests in), so the test framework
// ignores it.
Object.defineProperty(element._store, 'validated', {
configurable: false,
enumerable: false,
writable: true,
value: 0,
});
// debugInfo contains Server Component debug information.
Object.defineProperty(element, '_debugInfo', {
configurable: false,
enumerable: false,
writable: true,
value: null,
});
Object.defineProperty(element, '_debugStack', {
configurable: false,
enumerable: false,
writable: true,
value: debugStack,
});
Object.defineProperty(element, '_debugTask', {
configurable: false,
enumerable: false,
writable: true,
value: debugTask,
});
if (Object.freeze) {
Object.freeze(element.props);
Object.freeze(element);
}
}

return element;
}

image-20250614073503671
4、虚拟DOM:

1
2
3
4
5
const AppJSX = (<div className='App'>
<h1 className='title'>I am the title</h1>
<p className='description'>I am the description</p>
</div>)
console.log("🚀 ~ App ~ AppJSX:", AppJSX)

image-20250614074400799

虚拟DOM => 真实DOM 由ReactDOM.render()方法完成
5、ReactDOM.render()源码解析:
https://github.com/facebook/react/blob/v18.2.0/packages/react-dom/src/client/ReactDOMLegacy.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
export function render(
element: React$Element<any>,
container: Container,
callback: ?Function,
) {
if (__DEV__) {
console.error(
'ReactDOM.render is no longer supported in React 18. Use createRoot ' +
'instead. Until you switch to the new API, your app will behave as ' +
"if it's running React 17. Learn " +
'more: https://reactjs.org/link/switch-to-createroot',
);
}

if (!isValidContainerLegacy(container)) {
throw new Error('Target container is not a DOM element.');
}

if (__DEV__) {
const isModernRoot =
isContainerMarkedAsRoot(container) &&
container._reactRootContainer === undefined;
if (isModernRoot) {
console.error(
'You are calling ReactDOM.render() on a container that was previously ' +
'passed to ReactDOMClient.createRoot(). This is not supported. ' +
'Did you mean to call root.render(element)?',
);
}
}
return legacyRenderSubtreeIntoContainer(
null,
element,
container,
false,
callback,
);
}

image-20250614075552820

此页目录
2025-04-27 日报 Day169