1、JSX:
JSX代码中出现的标签既不是一个字符串,也不是HTML。
JSX是JavaScript的一种语法扩展。建议在React使用JSX编写代码,以让其更直观。JSX像一种模板语言,但可以使用JavaScript的全部特性。
JSX用于产生React元素。
1) 内嵌JavaScript表达式:
在JSX中可以内嵌任何有效的 JavaScript表达式 ,只需要将该表达式用一对花括号包裹即可。
可以将JSX换行缩进以提高代码的可读性,此时需要注意的是:为了避免 分号自动插入 的bug,即使只有一行JSX代码,仍然建议将JSX代码包裹在小括号里面。
2) JSX也是一种表达式:
编译完,JSX表达式变成了普通的JS对象。这意味着可以在if和for循环里面使用JSX,也可以把JSX赋值给变量,作为参数,或作为一个函数的返回值。
3) JSX属性的用法:
可以在一对引号中直接将字符串字面量作为属性值,也可以在一对花括号中直接使用JavaScript表达式作为属性值,但注意不要同时在一个属性里使用引号和花括号。
4) JSX子元素的用法:
如果一个标签为空,像XML一样添加 /> 自结束即可;也可以在JSX标签中嵌套子元素。
相比HTML,JSX更接近JavaScript,React DOM属性使用 驼峰式命名法代替HTML属性命名法。如,在JSX中 class 需要写作 className , tabindex 需要写作 tabIndex 。
5) JSX默认阻止注入攻击:
在JSX可以安全的嵌入渲染用户输入的内容;在渲染前React DOM默认对嵌入JSX中的值进行 编码 ,以确保应用中不会被注入任何不安全代码。任何值在渲染之前都会被转换为字符串,以避免 XSS (cross-site-scripting) 攻击。
6) JSX代表对象:
Babel将JSX编译为 React.createElement() 调用。React.createElement() 会做适当的检查来帮助开发者写0bug的代码,最终会生成对象,这些对象就是React元素,这些元素详细描述了最终在屏幕上如何展示,React通过这些对象构造DOM,并持续对其更新。
2、渲染元素
元素是React apps中最小的构建部件。一个元素描述的是希望屏幕上呈现的样子。
不同于浏览器的DOM元素,React元素只是一个对象,并且创建一个元素是非常廉价的。React DOM只需要更新DOM到对应的React元素上。
1) 在DOM里渲染元素:
HTML中的DOM节点称为根DOM节点,因为在它内部的一切都将被React DOM管理。
通常只有一个根DOM节点,当然也可以分离出多个根DOM节点。
通过ReactDOM.render() 方法,可以把React元素渲染到根DOM节点上。
2) 更新被渲染的元素:
React元素是不可变的。
当创建一个元素时,不能改变它们的子元素或属性。
唯一能更新UI的方式是创建一个新的元素并且传给ReactDOM.render()。
3) React只更新需要的部分:
ReactDOM会把元素当前的值,包括其子元素,与之前的值进行比较,并且只会进行必要的更新。
经验表明,应该思考的是在一个特定的时刻UI应该是什么样子,而不是怎样去改变它,这种思维方式能帮助减少很多bug。
3、组件和props
组件能把UI切割成独立的,可重用的部件,可以独立的思考每一个部件。
从概念上看,components 就像Javascript 的函数。允许任意的输入(props),并返回React元素,描述元素应该怎么显示在屏幕上。
1) 函数以及类组件:
A. 函数式组件:
定义组件最简单的方法就是写一个Javascript函数,这个函数是一个合法的React元素,因为它接收一个props对象参数并返回一个React元素。这样的组件称为函数式组件。
functionHelloReact(props) {
return Hello,{props.name}
;
}
B. 类组件:
可以使用ES6的class来定义一个组件。
classHelloReact extends React.Component {
render() {
return Hello, {this.props.name}
;
}
}
2) 渲染组件:
组件可以返回一个元素作为返回值,元素可以是HTML标签,也可以是用户定义的组件。
调用ReactDOM.render()方法渲染组件,当遇到一个用户定义的组件表示的元素时,React会把JSX里的属性作为一个对象传递到组件中,这个对象通常称为props。
组件的名字最好都是大写字母开头的,且要求是一个闭合标签。
3) 组合组件:
组件可以引用其他的组件作为输出。
组件必须返回一个根组件,一般用一个 4) 切割组件: 不要害怕把组件切割成更小的组件。 切割组件可能看起来像麻烦的工作,但对于一个大型的应用来说,拥有一个可重用的组件是一个回报很高的事情。 一个好的经验法则:如果UI中某些组件被重用了多次或者自身就足够复杂,将它们作为可重用的组件是一个好的选择。 5) props是只读的: 无论声明一个函数组件或一个类组件,它都不能修改props。 应用的UI是动态的并且经常变化的,这就需要引入state。 4、state和生命周期 state跟porps很相似,但是state是组件私有的,并受组件控制。 相比函数组件,类组件有一些额外的功能,比如添加state和生命周期。 1) 函数组件转化为类组件: 可以通过5步把函数组件转化为类组件: A. 创建一个同名的类组件并且继承React.Compoent; B. 添加一个空的方法叫做render(); C. 把函数里面的内容移到render方法里面; D. 把render()里面的props替换成this.props; E. 删掉之前的函数声明的组件。 2) 添加state到类组件: 可以通过3步把props移到state: A. 把render()方法里的this.props.*替换成 this.state.*; B. 添加constructor ()用来初始化this.state,注意将props作为参数传到constructor,在constructor函数体中执行super(props);当参数传递ReactDOM.render()时,React调用组件中的constructor函数。 C. 从元素中移除props。 3) 添加周期方法到类组件: 在有许多组件的应用里, 当组件被销毁的时候释放掉资源是非常重要的。 通常在类组件里声明一些特别的方法,当组件mounts和 unmounts的时候去运行这些方法,这些方法被称为生命周期方法钩子。 一个典型的实例是:在componentDidMount这个生命周期的函数方法中设置定时器,在componentWillUnmount这个生命周期的函数方法中卸载定时器。 4) 正确使用state: A. 别直接修改state的值 修改state的值请用setState(),不要直接对this.state赋值,唯一能声明this.state的地方只有在constructor里。 B. state的更新有可能是异步的 React 为了性能,可能会把批量处理多次的setState() 调用在一个的更新里。 因为this.props和this.state可能异步更新了,所有不应该依赖他们的值来计算下一个state。 为了解决这个问题,让setState()接收一个函数比接收一个对象的方式更好,这个函数会把前一个state作为第一个参数,更新的props作为第二参数: C. state的更新是合并后的 当调用setState()时,React会合并提供的对象到当前的state里,这意味着在state包含几个独立的变量时,能通过单独调用setState(),独立更新它们。 5) 单向数据流: 所有的父组件或者子组件都不知道一个组件是stateful或stateless的,并且它们也不应该关心自己是被定义成一个函数组件或者是类组件。 一个组件可能会把自己的state作为props传递给他们的子组件中,这就是单向数据流(从上往下)。任何的state都属于一些特定的组件,并且任何的数据或UI视图只能影响在其组件树下面的组件。 在React app里,无论一个stateful或stateless的组件都被认为组件独立的细节都可能随着时间而改变。能用stateless组件代替stateful组件,反之亦然。 5、处理事件 处理React元素事件跟处理DOM元素事件很相似,但有一些不同: React事件使用驼峰式命名的,而不是全小写。 JSX里要传递函数给事件处理,而不是字符串,也即应该用花括号而不能用引号。 不能通过return false来阻止默认事件,必须显示地调用e.preventDefault,这里的e是合成事件,React定义这些合成事件是根据W3C标准的,所以不需要担心浏览器兼容问题。 当用React时,当DOM被创建时,一般都不需要调用addEventListener来添加监听器到DOM上,相反,只需要在元素最初被渲染时添加一个监听器。当用es6的class定义一个组件时,一个通常的模式是在class上把事件处理定义一个方法。 注意this的指向,在事件处理函数内部的this不指向该组件,通常的解决方法是对事件处理函数进行bind(this)操作。this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}))