欢迎使用CSDN-markdown编辑器
来源:互联网 发布:阿里云市值 编辑:程序博客网 时间:2024/05/24 07:06
写在前面
最近在学React, 看了React官方的文章https://facebook.github.io/react/docs。 Quick Start部分的内容其实蛮好理解,例子也不错,只要跟着一步一步的做,还是很容易上手的。当Hello World带给我的喜悦渐渐褪去之后,回过头来,还是要再近一步看看React的细节。所以尝试翻译Advanced Guides部分。一方面督促自己仔细的阅读这几篇文章,一方面也留下一点资料以便自己之后阅读。
深度理解JSX
从本质上讲,JSX不过是给React.createElement(component, props, ...children)方法提供了一个语法糖,如下的JSX代码:
<MyButton color="blue" shadowSize={2}> Click Me</MyButton>
会被编译成下面这样:
React.createElement( MyButton, {color: 'blue', shadowSize: 2}, 'Click Me')
如果标签没有子节点的话,也可以使用单标签(自关闭形式self-close)的形式,所以:
React.createElement( <div className="sidebar" />)
会被编译成:
React.createElement( 'div', {className: 'sidebar'}, null)
如果你想测试一些特殊的JSX是如何被转化成Javascript的,可以尝试读读这个:the online Babel compiler
个人理解
在web前端技术还远没有像今天这样发达的10到15年前,java程序员们如果想使用html标签之外的自定义标签,不得不把html写到servlet里面去,然后在服务器端编译,再用JSP把相关的lib引入到页面,再由servlet编译成浏览器可以解析的html。如今这一过程再度上演,演员换成了前端框架React!
指定React元素类型
JSX标签的第一部分决定了React元素的类型。
首字母大写的类型意味着这个JSX标签来自于一个React component。这些标签可以看作是被编译成可直接引用的命名变量,所以如果你想使用JSX <Foo />
表达式,那Foo
必须在当前js文件的作用域中。
个人理解
- JSX的自定义标签,必须以大写字母开头
- 如果自定义标签的代码写在了单独的一个js文件里,在使用的时候,要import进来。
React必须在作用域之内
既然JSX会通过一个React.createElement
调用来进行’编译’,那React的lib必须总是在你JSX代码的作用域内生效的。
比如:下面的两个import是必须的,哪怕你的代码并没有直接的使用它们。
import React from 'react';import CustomButton from './CustomButton';function WarningButton() { // return React.createElement(CustomButton, {color: 'red'}, null); return <CustomButton color="red" />;}
如果你不使用javascript bundler(应该就是npm),而是直接从<script>
标签中引用React,那他应该就已经是一个全局的变量了。
使用Dot Notation来引用JSX的类型
你可以使用dot-notation的方式来引用这些JSX. 如果你有一个返回多个React component的单独模块,这会比较方便。比如: 如果MyComponents.DatePicker
是一个component, 你就可以在JSX代码里直接这样引用:
import React from 'react';const MyComponents = { DatePicker: function DatePicker(props) { return <div>Imagine a {props.color} datepicker here.</div>; }}function BlueDatePicker() { return <MyComponents.DatePicker color="blue" />;}
所谓的Dot Notation,就是程序员常说的”点”一下。
有的时候,我们可能会把一组相关的React的component定义在一个文件中。但是对外提供统一的引用变量。所谓相关的React的component,意思是: 比如把所有的form相关的component放到一起,或者把相关的数据容器(table, tree)等放到一起。
用户自定义的Components必须是大写字母开头
当元素的类型以小写字母开头的时候,它会被当作像<div>
或<span>
那样的内置的标签,以string:'div'
或'span'
传递给React.createElement
.像<Foo />
这种以大写字母开头的类型,会以Object的方式传递给React.createElement(Foo)
,并且对应到已经定义或引入的React component上。
我们推荐以大写字母来命名component。但是如果你已经有了一个以小写字母开头的component, 你也可以在JSX使用之前将它赋值给一个大写字母开头的变量。
比如,下面这段代码不会按照预期执行:
import React from 'react';// Wrong! This is a component and should have been capitalized:function hello(props) { // Correct! This use of <div> is legitimate because div is a valid HTML tag: return <div>Hello {props.toWhat}</div>;}function HelloWorld() { // Wrong! React thinks <hello /> is an HTML tag because it's not capitalized: return <hello toWhat="World" />;}
要解决这个问题,我们要把hello重新命名成Hello,并且用<Hello />
来引用
import React from 'react';// Correct! This is a component and should be capitalized:function Hello(props) { // Correct! This use of <div> is legitimate because div is a valid HTML tag: return <div>Hello {props.toWhat}</div>;}function HelloWorld() { // Correct! React knows <Hello /> is a component because it's capitalized. return <Hello toWhat="World" />;}
在运行时选择React类型
对于React的类型,你不能使用一般表达式。如果你想要使用一般表达式来引用元素类型的话,你可以先将表达式赋值给一个变量。比较常用的做法是,根据props值的不同来渲染不同的component:
import React from 'react';import { PhotoStory, VideoStory } from './stories';const components = { photo: PhotoStory, video: VideoStory};function Story(props) { // Wrong! JSX type can't be an expression. return <components[props.storyType] story={props.story} />;}
要解决这个问题,我们可以将‘类型’赋值给一个变量:
import React from 'react';import { PhotoStory, VideoStory } from './stories';const components = { photo: PhotoStory, video: VideoStory};function Story(props) { // Correct! JSX type can be a capitalized variable. const SpecificStory = components[props.storyType]; return <SpecificStory story={props.story} />;}
JSX中的Props
在JSX中,有几种不同的方式来指定props
用Javascript的表达式作为Props
你可以用大括号包裹任意Javascript表达式传递给props。比如,在JSX:
<MyComponent foo={1 + 2 + 3 + 4} />
对于MyComponent
来说,props.foo
的值将会是10,因为表达式1 + 2 + 3 + 4
的值就是10.
if
语句和for
循环在javascript里面都不是表达式,所以它们不能被直接用于JSX。取而代之的是,你可以把他们放到外部的代码中。比如:
function NumberDescriber(props) { let description; if (props.number % 2 == 0) { description = <strong>even</strong>; } else { description = <i>odd</i>; } return <div>{props.number} is an {description} number</div>;}
你可以在相应的条件渲染和循环中学到更多的知识。
字符串字面量
你可以像props传递字符串字面量。下面两个JSX表达式是等价的:
MyComponent message="hello world" /><MyComponent message={'hello world'} />
当你传递字符串字面量的时候,如果的它的值含有HTML保留字的时候,下面的两个JSX的表达式是等价的:
<MyComponent message="<3" /><MyComponent message={'<3'} />
这个行为通常来讲没有什么相关性,只是为了便于理解,在这里提及。
Props默认为TRUE
如果你不传递任何值给props,那它默认为true. 下面两个JSX表达式是等价的:
<MyTextBox autocomplete /><MyTextBox autocomplete={true} />
一般的,我们不推荐使用这个方式。因为它会和ES6 Object shorthand混淆。在ES6中,{foo}
意思是{foo:foo}
,而不是{foo:true}
。这个特性和HTML的特性是吻合的。
属性蔓延
如果你已经有了一个以对象形式存在的props,并且你希望在JSX中使用它。那你可以使用…作为操作符来传递整个props对象。下面两个components是等价的:
function App1() { return <Greeting firstName="Ben" lastName="Hector" />;}function App2() { const props = {firstName: 'Ben', lastName: 'Hector'}; return <Greeting {...props} />;}
当你想建立一个一般性的容器的时候,属性蔓延还是蛮有用的。但是,因为他们传递了许多无关的props给component,这会使你的代码显得笨重。我们建议保守的使用这个特性。
JSX中的子节点
包含开始标签和结束标签的JSX表达式,两个标签中的内容就是自标签。子标签作为一个特殊的props,以props.children
的形式在传递到标签中。这里有几种不同的方式来传递子标签:
字符串字面量
可以在开始和结束标签之间放入一个字符串,props.children会讲被这个字符串赋值。这对于内置的HTML标签很有用,比如:
<MyComponent>Hello world!</MyComponent>
这是一个合法的JSX的表达式,在MyComponent中props.children就是简单的字符串”Hello world!”。HTML包含保留字,所以你可以像写HTML那样的写JSX:
<div>This is valid HTML & JSX at the same time.</div>
JSX会自动删除一行中开始与结束的空格。当然,也会删除空行以及末尾的新行。在字面量中间出现的新行,会被浓缩成一行。所以,如下的方式,会被渲染成一样的效果:
<div>Hello World</div><div> Hello World</div><div> Hello World</div><div> Hello World</div>
JSX作为子标签
你可以提供更多的JSX元素作为子标签。他们对于嵌套的标签非常有用:
<MyContainer> <MyFirstComponent /> <MySecondComponent /></MyContainer>
你可以把不同类型的自标签混合,所以你可以同时将字符串字面量和JSX混合使用。这是JSX像HTML的另外一个方式:
<div> Here is a list: <ul> <li>Item 1</li> <li>Item 2</li> </ul></div>
一个React的组件不可以返回多个标签元素,但是一个单一个JSX表达式可以有多个子标签。所以如果你想让一个component渲染多个部分,可以用一个div将这些部分包裹起来。
Javascript表达式做子标签
你可以将任意Javascript表达式作为子标签,用大括号包裹起来就可以。例如:
<MyComponent>foo</MyComponent><MyComponent>{'foo'}</MyComponent>
这种方式通常用来渲染一个任意长度的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> );}
Javascript可以和其他类型的子标签混合使用。例如:
function Hello(props) { return <div>Hello {props.addressee}!</div>;}
用Function作为子标签
正常来讲,插入到JSX中的Javascript表达式将会被执行成个字符串,或一个React元素,或者一个列表。但是props.children的表现就像其他的props一样可以是任何有序的数据,而不仅仅是React渲染过的数据。比如,如果你有一个自定义个component, 可以将props.children作为一个回调:
// Calls the children callback numTimes to produce a repeated componentfunction Repeat(props) { let items = []; for (let i = 0; i < props.numTimes; i++) { items.push(props.children(i)); } return <div>{items}</div>;}function ListOfTenThings() { return ( <Repeat numTimes={10}> {(index) => <div key={index}>This is item {index} in the list</div>} </Repeat> );}
传递到自定义component中的子标签可以是任意数据和形式,只要这个component在渲染之前把它转化为React可理解的东西就可以了。
Booleans, Null和Undefined会被忽略
false, null, undefined, 和true都是合法的子标签。他们不会被渲染。所有这些JSX表达式会被统一的渲染成一个东西:
<div /><div></div><div>{false}</div><div>{null}</div><div>{undefined}</div><div>{true}</div>
这有助于有条件的渲染React component。JSX只在showHeader
是true
的情况下渲染<Header />
:
<div> {showHeader && <Header />} <Content /></div>
但是对于有些falsy value,就是一个例外,比如0。当判断条件是这些falsy value时,React component同样会被渲染。比如下面这段代码不会按照预期来执行,因为空字符串也会被打印:
<div> {props.messages.length && <MessageList messages={props.messages} /> }</div>
要解决这个问题,就要保证&&之前的代码始终得到的是boolean:
<div> <div> {props.messages.length > 0 && <MessageList messages={props.messages} /> }</div></div>
相反的,如果你像让false, true, null或者是undefined出现在页面上,那要先把他们转化成字符串:
<div> My JavaScript variable is {String(myVariable)}.</div>
原文转自:JSX In Depth
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 将ip转为整数以及整数转为ip的java实现
- 证券基础------------------------->证券基础
- Binary Apple Tree URAL
- fzu 2234
- linux-10 网络的基本配置
- 欢迎使用CSDN-markdown编辑器
- Day09
- XML解析之DOM4J
- Liunx(Centos6.5)上安装TensorFlow
- Unity自定义UI组件(十一) 雷达图、属性图
- MYSQL5.7中初次登陆修改root密码出现password子段不存在的情况
- textarea自动换行
- android 内存回收机制
- 2171上升子序列