Agenda
- JSX In Depth
- Booleans, Null, and Undefined Are Ignored
- Typechecking With PropTypes
- Refs and the DOM
- Context
Agenda
- JSX In Depth
- Booleans, Null, and Undefined Are Ignored
- Typechecking With PropTypes
- Refs and the DOM
- Context
JSX In Depth
Props Default to "True"
传递一个没有值的属性,其默认值是true
<MyTextBox autocomplete />
//is equal
<MyTextBox autocomplete={true} />
<MyTextBox autocomplete/>
console.log(this.props.autocomplete)
// true
<MyTextBox />
console.log(this.props.autocomplete)
// undefined
Spread Attributes
const Component1 = () => {
return <Greeting firstName="Ben" lastName="Hector" />
}
const Component2 = () => {
const props = {firstName: 'Ben', lastName: 'Hector'}
return <Greeting {...props} />;
}
高效但是混乱
We recommend that you use this syntax sparingly.
String Literals
自动删除行首/末位空格,删除空行
<div>Hello World</div>
<div>
Hello World
</div>
<div>
Hello
World
</div>
<div>
Hello World
</div>
Booleans, Null, and Undefined Are Ignored
Booleans(false & true), null, undefined都是合法值
<div />
<div></div>
<div>{false}</div>
<div>{null}</div>
<div>{true}</div>
全部 render null
const messages = []
<div>
{messages.length &&
<MessageList messages={messages} />
}
</div>
number '0'不会被转化为 false
<div>
{messages.length > 0 &&
<MessageList messages={messages} />
}
</div>
确保在&&前面的是booleans
若要显示‘false & true, null, undefined’,需转换为 string
<div>
My JavaScript variable is {String(myVariable)}.
</div>
Typechecking With PropTypes
我经常使用的 PropTypes
MyComponent.propTypes = {
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,
optionalSymbol: React.PropTypes.symbol,
}
限制在枚举的数组中
optionalEnum: React.PropTypes.oneOf(['News', 'Photos'])
限制在多个类型中
optionalUnion: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.instanceOf(Message)
])
限定数组中 value 的类型
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number)
限定对象中 value 的类型
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number)
限定数据结构
optionalObjectWithShape: React.PropTypes.shape({
color: React.PropTypes.string,
fontSize: React.PropTypes.number
})
shape只能用在对象中
optionalObjectWithShape: React.PropTypes.shape({
colors: React.PropTypes.shape({
backgroundColor: React.PropTypes.string.isRequired
})
自定义一个validator,异常情况 return Error 对象
customProp: (props, propName, componentName) => {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
)
}
}
可以用箭头函数
自定义arrayOf
和 objectOf
customArrayProp: React.PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
console.log('location', location)
//location prop
console.log('propFullName', propFullName)
//propFullName customArrayProp[0]
})
遍历每一个元素
Default Prop Values
会不会报错?
class Greeting extends React.Component {
static propTypes = {
name: PropTypes.string.isRequired
}
static defaultProps = {
name: 'Stranger'
}
render() {
return (
<h1>Hello, {this.props.name}</h1>
)
}
}
propTypes类型检查在defaultProps赋值后进行
Refs and the DOM
The ref Callback Attribute
ref 属性可以接受一个回调函数
并且在组件mounted和unmounted时立即调用
回调函数的参数是该 DOM element,unmounted的时候是 null
class CustomTextInput extends React.Component {
constructor(props) {
super(props)
this.handleFocus = this.handleFocus.bind(this)
}
handleFocus() {
this.textInput.focus()
}
render() {
return (
<div>
<input
type="text"
ref={(input) => { this.textInput = input }}
/>
<input
type="button"
value="Focus the text input"
onClick={this.handleFocus}
/>
</div>
)
}
}
class AutoFocusTextInput extends React.Component {
componentDidMount() {
this.customTextInput.handleFocus()
}
render() {
return (
<CustomTextInput
ref={(customTextInput) => { this.customTextInput = customTextInput }}
/>
)
}
}
class CustomTextInput extends React.Component {
handleFocus() {
this.textInput.focus()
}
render() {
return (
<input
ref={(input) => { this.textInput = input}
/>
)
}
}
Functional components
函数式组件,需要提前声明
function CustomTextInput(props) {
// textInput must be declared here so the ref callback can refer to it
let textInput = null
function handleClick() {
textInput.focus()
}
return (
<div>
<input
type="text"
ref={(input) => { textInput = input; }} />
<input
type="button"
value="Focus the text input"
onClick={handleClick}
/>
</div>
)
}
Don't Overuse Refs
Reconciliation
The Diffing Algorithm
Elements Of Different Types
<div>
<Counter />
</div>
<span>
<Counter />
</span>
这里的<Counter />
是一个完全新的组件,旧的状态都将清除
当根元素类型变化,毁掉旧的树,创建新的树
包含在树里的组件会被卸载,所有状态清空
DOM Elements Of The Same Type
<div className="before" title="stuff" />
<div className="after" title="stuff" />
类型相同,只更新属性
<div style={{color: 'red', fontWeight: 'bold'}} />
<div style={{color: 'green', fontWeight: 'bold'}} />
只更新 color,不更新 fontWeight
Recursing On Children
<ul>
<li>first</li>
<li>second</li>
</ul>
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
在末尾添加,前面的不会重新渲染
<ul>
<li> first </li>
<li> second </li>
</ul>
<ul>
<li> third </li>
<li> first </li>
<li> second </li>
</ul>
更新所有<li>
[slide]
{:&.bounceIn}
Keys
<ul>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
<ul>
<li key="2014">Connecticut</li>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
添加 key,更加高效
key 只需在兄弟节点中唯一
Context
Why Not To Use Context
如果希望稳定,一定不要用 context。
这是一个实验性 API,可能会在后续版本中移除
How To Use Context
不用 context ,组件结构如下:
class Button extends React.Component {
render() {
return (
<button style={{background: this.props.color}}>
{this.props.children}
</button>
)
}
}
class Message extends React.Component {
render() {
return (
<div>
{this.props.text} <Button color={this.props.color}>Delete</Button>
</div>
)
}
}
class MessageList extends React.Component {
render() {
const color = "purple";
const children = this.props.messages.map((message) =>
<Message text={message.text} color={color} />
)
return <div>{children}</div>
}
}
使用 context传递 props
class Button extends React.Component {
render() {
return (
<button style={{background: this.context.color}}>
{this.props.children}
</button>
)
}
}
Button.contextTypes = {
color: React.PropTypes.string
}
class Message extends React.Component {
render() {
return (
<div>
{this.props.text} <Button>Delete</Button>
</div>
)
}
}
class MessageList extends React.Component {
getChildContext() {
return {color: "purple"}
}
render() {
const children = this.props.messages.map((message) =>
<Message text={message.text} />
)
return <div>{children}</div>
}
}
添加childContextTypes 和 getChildContext
如果未定义contextTypes,context是一个空对象