记录JSX格式到react内部ReactElement的过程,主要经历编译和转换两个阶段。
JSX转React Element
下面这段JSX:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function App() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > test </a> </header> </div> ); }
|
转换为React Element为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function App() { return React.createElement("div", { className: "App" }, React.createElement("header", { className: "App-header" }, React.createElement("img", { src: logo, className: "App-logo", alt: "logo" }), React.createElement("p", null, "Edit ", React.createElement("code", null, "src/App.js"), " and save to reload."), React.createElement("a", { className: "App-link", href: "https://reactjs.org", target: "_blank", rel: "noopener noreferrer" }, "test"))); }
|
createElement
createElement(type, config, children)函数位于: src/react/packages/react/src/ReactElement.js
。
JSX转换之后会调用这个方法,这个函数内部也是先后处理这三个参数,将处理后的参数传入ReactElement()
函数中,创建React Element。
ReactElement
ReactElement(type, key, ref, self, source, owner, props)位于: src/react/packages/react/src/ReactElement.js
。
执行结果返回一个普通js对象,包含下面的参数:
1 2 3 4 5 6 7 8 9 10 11 12 13
| const element = { $$typeof: REACT_ELEMENT_TYPE,
type: type, key: key, ref: ref, props: props,
_owner: owner, };
|
$$typeof
属性值是一个Symbol类型,参考1中描述了$$typeof
存在的意义。
比如服务器存在一个漏洞,可以接受任意的json,前端代码某处需要的是一个字符串,如果后端返回一个恶意的React Element,就有可能注入到前端。Symbol类型的一个特点是不能通过Json进行传递,所以react内部会检查每一个React Element的$$typeof
属性,保证合法性。
react使用Symbol.for
这个api在全局池中进行这种类型的创建,特点详见参考2。
react中Symbol类型的定义位于:/src/react/packages/shared/ReactSymbols.js
。
参考资料
- https://overreacted.io/why-do-react-elements-have-typeof-property/
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for
全文完。