欧美做暖网站,html个人网站源码,php网站开发目的,外贸公司几个网站什么是 JSXJSX 是一个 JavaScript 的语法扩展。JSX 可能会使人联想到模版语言#xff0c;但它具有 JavaScript 的全部功能在 React 中#xff0c;JSX 仅仅是 React.createElement(component, props, ...children) 函数的语法糖如下 JSX 代码#xff1a;MyButton color但它具有 JavaScript 的全部功能 在 React 中JSX 仅仅是 React.createElement(component, props, ...children) 函数的语法糖如下 JSX 代码MyButton colorblue shadowSize{2}Clicke Me
/MyButton
会编译为React.createElement(MyButton,{color: blue, shadowSize: 2},Click Me
)
React 必须在作用域内由于 JSX 会编译为 React.createElement 调用形式所以 React 库也必须包含在 JSX 代码作用域内如果不使用打包工具而是直接通过 script 标签加载 React则必须将 React 挂载到全局变量中用户自定义的组件必须以大写字母开头以小写字母开头的元素代表一个 HTML 内置组件比如 div 或者 span 会生成相应的字符串 div 或者 span 传递给 React.createElement作为参数。大写字母开头的元素则对应着在 JavaScript 引入或自定义的组件如 Foo / 会编译为 React.createElement(Foo)JSX 语法在 JSX 中嵌入表达式在 JSX 语法中你可以在打括号内放置任何有效的 JavaScript 表达式function formatName(user) {return user.firstName user.lastName;
}const user {firstName: Harper,lastName: Perez
}const element (h1Hello, {formatName(user)}!/h1
)ReactDOM.render(element,document.getElementById(root)
)
JSX 也是一个表达式在编译后JSX 表达式会被转为普通 JavaScript 函数调用并且对其取值后得到 JavaScript 对象function getGreeting(user) {if (user) {return h1Hello, {formatName(user)}!/h1;}return h1Hello, Stranger./h1;
}JSX 特定属性在属性中嵌入 JavaScript 表达式时不要在大括号外面加上引号。你应该仅使用引号对于字符串值或大括号对于表达式中的一个对于同一属性不能同时使用这两种符号。const element img src{user.avatarUrl}/img
因为 JSX 语法上更接近 JavaScript 而不是 HTML所以 React DOM 使用 camelCase小驼峰命名来定义属性的名称而不使用 HTML 属性名称的命名约定。使用 JSX 指定子元素假如一个标签里面没有内容你可以使用 / 来闭合标签就像 XML 语法一样const element img src{user.avatarUrl} /
JSX 标签里能够包含很多子元素const element (divh1Hello!/h1h2Good to see you here./h2/div
)
JSX 防止注入攻击React DOM 在渲染所有输入内容之前默认会进行转义。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSScross-site-scripting, 跨站脚本攻击。JSX 表示对象Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用以下两种示例代码完全等效const element (h1 classNamegreetingHello, world!/h1
)const element React.createElement(h1,{className: greeting},Hello, world!
)
JSX 中的 PropsJavaScript 表达式作为 PropsMyComponent foo{1 2 3 4} /
字符串字面量以下两个 JSX 表达式是等价的MyComponent messagehello world /MyComponent message{hello world} /
当你将字符串字面量赋值给 prop 时它的值是未转义的以下两个 JSX 表达式是等价的MyComponent messagelt;3 /MyComponent message{3} /
Props 默认值为 true以下两个 JSX 表达式是等价的MyTextBox autocomplete /MyTextBox autocomplete{true} /
属性展开可以使用展开运算符 ... 来在 JSX 中传递整个 props 对象。以下两个组件是等价的function App1() {return Greeting firstNameBen lastNameHector /;
}function App2() {const props {firstName: Ben, lastName: Hector};return Greeting {...props} /;
}
JSX 中的子元素包含在开始和结束标签之间的 JSX 表达式内容将作为特定属性 props.children 传递给外层组件。有几种不同的方法来传递子元素字符串字面量MyComponentHello world!/MyComponent
编译为divThis is valid HTML amp; JSX at the same time./div
JSX 会移除行首尾的空格以及空行。与标签相邻的空行均会被删除文本字符串之间的新行会被压缩为一个空格。因此以下的几种方式都是等价的divHello World/divdivHello World
/divdivHelloWorld
/divdivHello World
/div
JSX 子元素MyContainerMyFirstComponent /MySecondComponent /
/MyContainer
JavaScript 表达式作为子元素JavaScript 表达式可以被包裹在 {} 中作为子元素。以下表达式是等价的MyComponentfoo/MyComponentMyComponent{foo}/MyComponent
这对于展示任意长度的列表非常有用。例如渲染 HTML 列表function Item(props) {return li{props.message}/li;
}function TodoList() {const todos [finish doc, submit pr, nag dan to review];return (ul{todos.map((message) Item key{message} message{message} /)}/ul);
}
函数作为子元素你可以将任何东西作为子元素传递给自定义组件只要确保在该组件渲染之前能够被转换成 React 理解的对象。这种用法并不常见但可以用于扩展 JSX。function Item(props) {return li{props.message}/li;
}function TodoList() {const todos [finish doc, submit pr, nag dan to review];return (ul{todos.map((message) Item key{message} message{message} /)}/ul);
}
布尔类型、Null 以及 Undefined 将会忽略false, null, undefined, and true 是合法的子元素。但它们并不会被渲染。以下的 JSX 表达式渲染结果相同div /div/divdiv{false}/divdiv{null}/divdiv{undefined}/divdiv{true}/div
这有助于依据特定条件来渲染其他的 React 元素。例如在以下 JSX 中仅当 showHeader 为 true 时才会渲染 Header / 组件div{showHeader Header /}Content /
/div
值得注意的是有一些 “falsy” 值如数字 0仍然会被 React 渲染。例如以下代码并不会像你预期那样工作因为当 props.messages 是空数组时0 仍然会被渲染div{props.messages.length MessageList messages{props.messages} /}
/div
要解决这个问题确保 之前的表达式总是布尔值div{props.messages.length 0 MessageList messages{props.messages} /}
/div
反之如果你想渲染 false、true、null、undefined 等值你需要先将它们转换为字符串divMy JavaScript variable is {String(myVariable)}.
/div
JSX 的本质JavaScript 的语法扩展React 官网给出的一段定义JSX 是一个 JavaScript 的语法扩展。JSX 可能会使人联想到模版语言但它具有 JavaScript 的全部功能那么 “JSX 语法时如何在 JavaScript 中生效的”JSX 语法是如何在 JavaScript 中生效的认识 BabelJSX 定位是 JavaScript 的“扩展”这就直接决定了浏览器不会天然支持 JSX。那么JSX 的语法是如何在 JavaScript 中生效的呢React 官网给出了答案JSX 会被编译为 React.createElement() React.createElement() 将返回一个叫作“React Element”的 JS 对象。“编译” 这个动作是由 Babel 来完成的什么是BabelBabel 是一个工具链主要用于将 ECMAScript 2015 版本的代码转换为向后兼容的 JavaScript 语法以便能够运行在当前和旧版本的浏览器或其他环境中。 —— Babel 官网例如箭头函数// Babel 输入 ES2015 箭头函数
[1, 2, 3].map((n) n 1);// Babel 输出 ES5 语法实现的同等功能
[1, 2, 3].map(function(n) {return n 1;
});
类似的Babel 也具备将 JSX 语法转换为 JavaScript 代码的能力看看开头的示例我们写的 JSX 其实写的就React.createElement虽然它看起来有点像 HTML但也只是“看起来像”而已。JSX 的本质是 React.createElement 这个 JavaScript 调用的语法糖这也呼应了 React 官方给出的“JSX 充分具备 JavaScript 的能力”这句话。为什么选择 JSX既然 JSX 等价于一次 React.createElement 调用为什么不直接使用 React.createElement 来创建元素呢原因很简单在效果一致的前提下JSX 代码层次分明、嵌套关系清晰而 React.createElement 代码混乱杂糅不仅难以阅读也难以编码JSX 语法糖允许前端开发者使用我们最为熟悉的类 HTML 标签语法来创建虚拟 DOM在降低学习成本的同时也提升了研发效率与研发体验。React 官网也提出React 并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式而是通过将二者共同存放在称之为“组件”的松散耦合单元之中来实现关注点分离。JSX 是如何映射为 DOM 的阅读 createElement 源码我们先大致理解 createElement 函数源码的作用//注意react只写了3个参数实际上从第三个参数往后都是children
export function createElement(type, config, children) {let propName; // 用于存储后面需要用到的元素属性// Reserved names are extractedconst props {}; // 用于存储元素属性的键值对集合let key null;let ref null;let self null;let source null;// 赋给标签的props不为空时// config 存储元素的属性if (config ! null) {// 依次对 ref、key、self 和 source 属性赋值if (hasValidRef(config)) {ref config.ref;}if (hasValidKey(config)) {// 防止是Numberkey config.key;}//__self、__source 暂时不知道是干啥用的属性self config.__self undefined ? null : config.__self;source config.__source undefined ? null : config.__source;// Remaining properties are added to a new props objectfor (propName in config) {// 如果config中的属性不是标签原生属性则放入props对象中if (hasOwnProperty.call(config, propName) !RESERVED_PROPS.hasOwnProperty(propName)) {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);// 依次将children push进array中for (let i 0; i childrenLength; i) {childArray[i] arguments[i 2];}// 开发中写的this.props.children就是子元素的集合props.children childArray;}// Resolve default props// 为传入的props设置默认值比如//class Comp extends React.Component{// static defaultProps {// aaa: one,// bbb: () {},// ccc: {},// };//// }if (type type.defaultProps) {const defaultProps type.defaultProps;for (propName in defaultProps) {// 如果props数组中未设值则设置默认值注意null也算设置了值if (props[propName] undefined) {props[propName] defaultProps[propName];}}}return ReactElement(type, //divkey, //nullref, //nullself, //nullsource, //nullReactCurrentOwner.current, // null或Fiberprops, // 自定义的属性、方法注意props.childrenchildArray);
}
参数创建一个元素需要哪些信息export function createElement(type, config, children)
type用于表示节点的类型。它可以是标准 HTML 标签字符串也可以是 React 组件类型或 React Fragment 类型config以对象形式传入组件所有的属性都会以键值对的形式存储在 config 对象中children以对象形式传入它记录的是组件标签之间嵌套的内容也就是所谓的 “子节点” “子元素”下面的示例可以帮助增进对 createElement 的理解React.createElement(div, {className: wrapper
}, React.createElement(h1, {className: header
}, header), React.createElement(p, {className: content
}, content))
对应的 DOM 结构div classwrapperh1 classheaderheader/h1p classcontentcontent/p
/div
createElement 分析逻辑流程图createElement 中并没有复杂的逻辑它的每一步步骤几乎都是在格式化数据createElement 就如同是开发者和 ReactElement 调用之间的一个 “转换器”对数据进行处理返回值初识虚拟 DOMcreateElement 执行到最后会 return 一个 ReactElement 的调用下面是关于 ReactElement 的源码及解析const ReactElement function(type, key, ref, self, source, owner, props) {const element {// REACT_ELEMENT_TYPE是一个常量用来标识该对象是一个ReactElement$$typeof: REACT_ELEMENT_TYPE,// 内置属性赋值type: type,key: key,ref: ref,props: props,// 记录创造该元素的组件_owner: owner,};if (__DEV__) {}return element;
};ReactElement 只做了一件事那就是创建ReactElement 把传入的参数按照一定的规范“组装”进 element 对象并将它返回给 React.createElement最终 React.createElement 又将它返回到开发者对于 ReactElement 对象实例其本质上是以 JavaScript 对象形式存在的对 DOM 的描述也就是 “虚拟 DOM”更准确地说是虚拟 DOM 中的一个节点从虚拟 DOM 到真实 DOM 需要调用 ReactDOM.render 方法在每个 React 项目的入口文件中都有对 React.render 函数的调用。下面是 ReactDOM.render 的函数签名ReactDOM.render(// 需要渲染的元素ReactElementelement,// 元素挂载的目标容器真实 DOMcontainer,// 回调函数用于处理渲染结束后的逻辑。可选[callback]
)
总结JSX 经过 babel 转换为 React.createElement 函数再调用 React.createElement 和 ReactElement 返回一个 element 对象虚拟 DOM最后通过 React.render 函数的调用生产真实 DOM 节点并挂载到 “容器” 上。