JSX语法
JSX中使用变量就是一个{}花括号括起来就行了,对属性而言,使用””双引号赋值字面量或使用{}插入js表达式。
| 12
 
 | const element = <div tabIndex="0"></div>;const element = <img src={user.avatarUrl}></img>;
 
 | 
react DOM使用小驼峰的写法。
标签里面如果没有内容,用直接使用</>闭合标签,如果包含许多子元素,用()
| 12
 3
 4
 5
 6
 
 | const element = <img src={user.avatarUrl} />;const element = (
 <h1 className="greeting">
 Hello, world!
 </h1>
 );
 
 | 
在安全方面,JSX直接使用用户输入的内容,因为react DOM会对输入进行转译,转为字符串避免
。
Babel将JSX转译React.createElement() 函数,函数创建一个对象,这样的对象被称为react元素。
| 12
 3
 4
 5
 6
 7
 
 | const element = {type: 'h1',
 props: {
 className: 'greeting',
 children: 'Hello, world!'
 }
 }
 
 | 
渲染
元素渲染
react元素是创建开销极小的对象,使用ReactDOM.render()将react元素渲染到dom上
| 12
 
 | const element = <h1>Hello, world</h1>;ReactDOM.render(element, document.getElementById('root'));
 
 | 
更新渲染
react元素不可变,代表某个特定时期的ui,更新ui的方法是创建一个全新的元素,并使用ReactDOM.render()。一般来说,ReactDOM.render()只会调用一次。官网使用setInterval定时器来展示时间的更新。
与vue的虚拟DOM类似,也是只更新改变了部分。
组件
组件包含函数组件和class组件
函数组件是指接收的参数是一个对象,并返回一个react元素的组件。
| 12
 3
 
 | function Welcome(props) {return <h1>Hello, {props.name}</h1>;
 }
 
 | 
class组件使用es6中的class继承React.Component来定义组件
| 12
 3
 4
 5
 
 | class Welcome extends React.Component {render() {
 return <h1>Hello, {this.props.name}</h1>;
 }
 }
 
 | 
渲染
渲染用户自定义组件发生了什么
| 12
 3
 4
 5
 6
 7
 
 | function Welcome(props) {  return <h1>Hello, {props.name}</h1>;}
 const element = <Welcome name="Sara" />;
 ReactDOM.render(
 element,
 document.getElementById('root')
 );
 
 | 
首先,定义好welcome组件和element,调用ReactDOM.render,对传入的element即<Welcome name=”Sara” />中的自定义组件welcome进行调用,传入{name: ‘Sara’},组件返回<h1>Hello, Sara</h1>。然后在id为root的元素中渲染<h1>Hello, Sara</h1>。
注意自定义组件的名称需要大写,小写会被react认为是原生标签。
组合组件
就是在组件中也可以使用其他组件
提取组件
将耦合的代码变成一个个组件,提高可维护性
props不可更改
也就是说react组件对于传入的props,不能修改它的值
state与生命周期
state与props类似,state是私有并完全受控于当前组件。
将函数组件转为class组件主要注意的是将props替换为this.props。
为class组件添加局部state的步骤:this.props替换成this.state。添加constructor构造函数,为this.state赋初值,通过props来调节父类的构造函数
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | class Clock extends React.Component {constructor(props) {
 super(props);
 this.state = {date: new Date()};
 }
 render() {
 return (
 <div>
 <h1>Hello, world!</h1>
 <h2>It is {this.state.date.toLocaleTimeString()}.</h2>      </div>
 );
 }
 }
 
 ReactDOM.render(
 <Clock />,  document.getElementById('root')
 );
 
 | 
注意JS中为子类添加构造函数需要super开头,并且里面的语句都以;结尾。
生命周期
componentDidMount() 方法会在组件已经被渲染到 DOM 中后运行
componentWillUnmount() 生命周期方法中清除
使用 this.setState() 来时刻更新组件的state
使用state需要注意:
- 不直接修改state,而是使用setState(),在构造函数中唯一给this.state赋值。
| 1
 | this.setState({comment: 'Hello'});
 | 
- state与props可能是异步更新的,通过让state接收一个函数而不是对象来解决
| 12
 3
 
 | this.setState((state, props) => ({counter: state.counter + props.increment
 }));
 
 | 
数据向下流动
组件无法获知其他组件的状态,state除了拥有和设置了它的组件,其他组件是无法访问的。但是组件也可以选择将state作为props向下传递给子组件
| 12
 3
 
 | <h2>It is {this.state.date.toLocaleTimeString()}.</h2>自定义组件:
 <FormattedDate date={this.state.date} />
 
 | 
子组件是无法知道参数传入的数据是来自父组件的state还是props,还是手动输入的。单向数据流是指state总是属于特定的组件,并且只能影响树中”低于”它们的组件。
事件处理
在react的JSX语法中需要使用{}传入函数作为事件处理函数,并且不能返回false阻止默认行为,必须使用preventDefault。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | function ActionLink() {function handleClick(e) {
 e.preventDefault();
 console.log('The link was clicked.');
 }
 return (
 <a href="#" onClick={handleClick}>
 Click me
 </a>
 );
 }
 
 | 
为元素添加监听器可以在初始渲染时就添加。
当使用class定义时,常见做法是将事件处理函数声明以一个方法,特别需要注意其中this的绑定
| 1
 | this.handleClick = this.handleClick.bind(this);
 | 
这样绑定是为了当(子组件)调用时指向的是父组件的this,因为JS中class是不会默认绑定this的,也可以使用箭头函数来绑定。
| 12
 3
 4
 5
 
 | return (<button onClick={() => this.handleClick()}>
 Click me
 </button>
 )
 
 | 
但是存在一个性能问题:当函数作为props传入子组件时,组件有可能进行额外渲染。所以建议在构造函数中绑定this或者使用class fields(实验阶段)
| 12
 3
 
 | handleClick = () => {console.log('this is:', this);
 }
 
 | 
传参
向事件处理函数传参,可以使用以下两种方法,箭头函数和通过Function.prototype.bind
| 12
 
 | <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button><button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
 
 | 
使用箭头函数,事件对象需要显式传递,bind方法的话,事件对象及更多参数通过隐式传递
条件渲染
通过if或条件运算符来选择渲染哪个组件,可以用变量来保存元素,然后直接使用变量
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | if (isLoggedIn) {button = <LogoutButton onClick={this.handleLogoutClick} />;
 } else {
 button = <LoginButton onClick={this.handleLoginClick} />;
 }
 return (
 <div>
 <Greeting isLoggedIn={isLoggedIn} />
 {button}
 </div>
 );
 
 | 
运算符
与&&
| 12
 3
 4
 5
 
 | {unreadMessages.length > 0 &&<h2>
 You have {unreadMessages.length} unread messages.
 </h2>
 }
 
 | 
直接在{}中使用&&,当左边为true时右边才会执行,否则不执行。
三目运算同样也可以使用。
阻止组件渲染
通过render方法返回null,让组件不进行渲染。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 
 | function WarningBanner(props) {if (!props.warn) {    return null;  }
 return (
 <div className="warning">
 Warning!
 </div>
 );
 }
 
 class Page extends React.Component {
 constructor(props) {
 super(props);
 this.state = {showWarning: true};
 this.handleToggleClick = this.handleToggleClick.bind(this);
 }
 
 handleToggleClick() {
 this.setState(state => ({
 showWarning: !state.showWarning
 }));
 }
 
 render() {
 return (
 <div>
 <WarningBanner warn={this.state.showWarning} />
 <button onClick={this.handleToggleClick}>
 {this.state.showWarning ? 'Hide' : 'Show'}
 </button>
 </div>
 );
 }
 }
 
 ReactDOM.render(
 <Page />,
 document.getElementById('root')
 );
 
 | 
这段官网的例子中,子组件WarningBanner是否渲染取决于Page中showWarning的值,组件WarningBanner需要对props传入的warn值进行判断,看是否返回null。
列表&key
渲染多个组件
| 12
 3
 4
 
 | const numbers = [1, 2, 3, 4, 5];const listItems = numbers.map((number) =>
 <li>{number}</li>
 );
 
 | 
用map方法来遍历生成5个li标签,然后直接渲染listItems。
直接运行会有警告,原因时缺少key属性
| 12
 3
 4
 5
 
 | const listItems = numbers.map((number) =><li key={number.toString()}>
 {number}
 </li>
 );
 
 | 
通过toString来作为key,来标识每个元素,通常我们是通过id作为key,不建议用index,因为当顺序发生变化时,使用index会导致性能变差。
key值应该在被使用时才指定,或者在map()中设置。
key在兄弟节点中需要是唯一的,不需要全局唯一。