翻译一下官网 ,顺便了解一下React 16版本的新特性
照旧,从Hello World开始
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
在集成了React的必要的依赖,适配了jsx之后,页面会显示“ Hello World! ”
接下来介绍React的核心。
JSX
const element = <h1>Hello, world!</h1>;
element标签不是string也不是html元素,而是jsx,它是js的语法糖。React推荐使用jsx去render UI。jsx可能让你想起模板语言,但是它完全支持js语法。
为什么要用jsx
jsx不是react必须的,但是jsx可以更加便捷的处理虚拟DOM(处理事件,更新数据,渲染UI,并且规范的写法可以避免跨站攻击等)。更多人越来越适应和推荐jsx,毕竟是语法糖嘛!
jsx 如何render Object
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
以上两段代码等效,最终生成的Object可以认为为
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
React.createElement() 除了生成Object,也会对语法做校验,避免书写bug(可以看看element,结构简单时候还好,如果结构复杂,那么很容易书写错误,React.createElement()帮我们减少了创建对象的复杂度)
element对象叫做"React elements",你记忆理解为这种对象是一种描述,React读到这种描述信息,然后在浏览器构建真实的DOM并且监听他们的状态更新。
React elements
React elements是immutable(不可变的),一旦你创建了一个元素,你就不能修改它的属性或者子类,就好比是一个电影画面,不同时刻会描绘不同的画面。就我们所掌握的,更新UI的唯一方法是创建一个新的元素,然后通过ReactDOM.render()更新。
React只在某些条件下更新(对比之前创建的元素,比较属性和子类,只会更新state改变的dom)
Components and Props
组建其实就是函数
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
或者ES6写法
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
两者是等效的
react是严格的,也有一套简单的原则:All React components must act like pure functions with respect to their props
state
state的更新是异步的
不能直接赋值。只能通过constructor更新(this.setState())更新
//之前没有注意过这种使用方式
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
// 或者
// Correct
this.setState(function(state, props) {
return {
counter: state.counter + props.increment
};
});
处理事件
e.preventDefault(); // 阻止默认行为 ,cross-browser react遵循w3c标准并且做了兼容 。
不能用 return false去阻止(之前不知道或者未有尝试)
书写的规范
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// This syntax ensures `this` is bound within handleClick
return (
<button onClick={(e) => this.handleClick(e)}>
Click me
</button>
);
}
}
这么写是为了绑定this。但是在render里面赋值事件有不好的地方,官网是这么解释的:
The problem with this syntax is that a different callback is created each time the LoggingButton renders. In most cases, this is fine. However, if this callback is passed as a prop to lower components, those components might do an extra re-rendering. We generally recommend binding in the constructor or using the class fields syntax, to avoid this sort of performance problem.
如果这个事件方法要作为prop传递给更低级的组件,这些组件可能要有额外的re-rendering,我们尽量使用箭头函数或者是在constructor里面声明方法来避免这种问题。
传递参数 (Passing Arguments to Event Handlers)
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
两者等效,这里比较推荐bind,因为箭头函数(arrow function)需要传递e,bind方式会自动传递(forwarded)
tips
- It works because in JavaScript, true && expression always evaluates to expression, and false && expression always evaluates to false.
- Returning null from a component’s render method does not affect the firing of the component’s lifecycle methods. For instance componentDidUpdate will still be called.
Keys
Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity
不推荐使用index赋值key,且key只有在数组render的jsx元素当中才会有意义。且两个组件render的数据一致时候,key没有必要区分不同(例如List A element 和List B element render的li列表 key可以一致 ),key也不能当作props传递(自组件没法获取赋组件的key值)
规范
Keep in mind that if the map() body is too nested, it might be a good time to extract a component。
为了友好的render,尽量组件化(这里不止map,逻辑复杂也可以抽取,这个个人建议,拆分逻辑有助于提取和更新)
Form元素
html的form元素和React的表单元素有一些不同,因为表单元素通常是保持一些内部状态,比方说以下这段代码,表单元素就保留name属性
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
form组件被称为受控组件(controlled component)
受控组件(Controlled Components )
HTML中,input,textarea,select等通常基于用户的输入来保持和更新他们的状态,而在React当中,状态被作为组件本身的属性,并且只能通过setState()来更新。
React结合了这两者(既可以输入,又可以setState()),我们管这种元素(表单元素)叫做受控组件。
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
以上为React的实现
textarea 标签
HTML当中,textarea的用法如下:
<textarea>
Hello there, this is some text in a text area
</textarea>
React当中,textarea 的内容都要赋值给value属性
<textarea value={this.state.value} onChange={this.handleChange} />
select 标签
HTML操作select的状态比较繁琐,要标记option标签的selected属性来说明选中项
<select>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option selected value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
React则很方便,同样给select添加value属性。
<select value={this.state.value} onChange={this.handleChange}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
其他的类似inputs 不再赘述