Hello everyone, I'm Casson.
Recently, a new book about React
has been handed in (expected to be published by the end of the year), and there is a lot of time.
While I still remember the internal running process of React
, try to copy a React
big-react in my spare time.
Since it is a replica React
, it must run through some official test cases.
I encountered a very interesting problem when running a use case. The following is the troubleshooting process.
Welcome to join the human high-quality front-end framework group , with flying
problem phenomenon
Here's what this use case looks like:
it('uses the fallback value when in an environment without Symbol', () => {
expect((<div />).$$typeof).toBe(0xeac7);
});
He tested whether the internal attribute ---ca25edf5855134665c947f430fe25524 jsx
of $$typeof
is correct in an environment that does not support Symbol .
We know that jsx
is just the syntactic sugar of JS
, which will be compiled into function calls at compile time, for example:
// 编译前
<div />
// 编译后 React17之前
React.createElement('div');
// 编译后 React17之后
jsxRuntime.jsx('div');
In the implementation of the React.createElement
(or jsxRuntime.jsx
) method, the following data structure is finally returned:
const element: ReactElement = {
$$typeof: REACT_ELEMENT_TYPE,
type,
key,
ref,
props
};
The $$typeof
attribute is used to distinguish the type of jsx object , such as REACT_ELEMENT_TYPE
represents this jsx对象
is a React Element
.
In environments that support Symbol
, $$typeof
corresponds to a unique symbol
. In unsupported environments, corresponds to a hexadecimal number.
For example REACT_ELEMENT_TYPE
is defined as follows:
const supportSymbol = typeof Symbol === 'function' && Symbol.for;
export const REACT_ELEMENT_TYPE = supportSymbol
? Symbol.for('react.element')
: 0xeac7;
Back to our test case, his test intention is obvious: in an environment that does not support Symbol
, the div corresponding to the $$typeof
attribute of the jsx object should return a number 0xeac7
.
it('uses the fallback value when in an environment without Symbol', () => {
expect((<div />).$$typeof).toBe(0xeac7);
});
So how do you make an environment that doesn't support Symbols ?
很简单,在所有用例执行前的beforeEach
函数( jest
的)中将global.Symbol
置undefined
:
beforeEach(() => {
jest.resetModules();
originalSymbol = global.Symbol;
// 制造不支持Symbol的环境
global.Symbol = undefined;
React = require('react');
ReactDOM = require('react-dom');
ReactTestUtils = require('react-dom/test-utils');
});
When react
and react-dom
are introduced, the internal execution is global.Symbol === undefined
.
This simulates an environment that does not support Symbols .
But this use case hangs:
The above code should be no problem, after all, it is the use React
that the official will run. So where is the problem?
babel's pot
When React17
was released, it brought a brand new JSX transformation .
Before 17, jsx
will be compiled as React.createElement
, after 17 will be compiled as jsxRuntime.jsx
.
At the same time, the following statement will be introduced at the top of the module:
import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";
Execution of the above-introduced statement precedes the following statement:
originalSymbol = global.Symbol;
global.Symbol = undefined;
Therefore, when the statement is executed, there is still global.Symbol
in the environment, which causes the problem mentioned in the opening paragraph.
Then why React
there is no problem when running the official use case?
The answer is: React
will compile ---d0221215bcd320717a60e9bd46fd7339 jsx
to React.createElement
when running the use case.
This will not insert a new import statement at the top of the module.
When ---3cc600023e84f3e0e38907a17a0b2bde--- is introduced, React
global.Symbol
longer exists in the environment:
originalSymbol = global.Symbol;
global.Symbol = undefined;
React = require('react');
ReactDOM = require('react-dom');
ReactTestUtils = require('react-dom/test-utils');
Summarize
Since the compilation is done in memory, it is not easy to troubleshoot the compiled code. So if you don't have a deep understanding of the characteristics of React
, this problem is really not easy to troubleshoot.
At present, the amount of big-react code is still relatively small. For those who are interested in implementing it from 0 React
, you can pay attention and give a star
oh~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。