React简介
React 应用程序的组成部分: 元素和组件
元素
JSX语法介绍
我们建议使用 JSX 来编写你的 UI 组件。每个 JSX 元素都是调用 React.createElement() 的语法糖。一般来说,如果你使用了 JSX,就不再需要调用以下方法。
1 | const element = <h1>Hello, world!</h1>; |
jsx也是一个表达式,意味着可以进行函数渲染
1 | function getGreeting(user) { |
JSX的特定属性
1 | const element = <div tabIndex="0"></div>; |
警告:
因为 JSX 语法上更接近 JavaScript 而不是 HTML,所以 React DOM 使用 camelCase(小驼峰命名)来定义属性的名称,而不使用 HTML 属性名称的命名约定。
例如,JSX 里的 class 变成了 className,而 tabindex 则变为 tabIndex。
JSX 表示对象
Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。
以下两种示例代码完全等效:
1 | const element = ( |
react元素不可变性
React 元素是不可变对象。一旦被创建,你就无法更改它的子元素或者属性。一个元素就像电影的单帧:它代表了某个特定时刻的 UI。
React DOM 会将元素和它的子元素与它们之前的状态进行比较,并只会进行必要的更新来使 DOM 达到预期的状态。
组件
组件也可以被定义为可被包装的函数
定义组件最简单的方式就是编写 JavaScript 函数:
1 | function Welcome(props) { |
该函数是一个有效的 React 组件,因为它接收唯一带有数据的 “props”(代表属性)对象与并返回一个 React 元素。这类组件被称为“函数组件”,因为它本质上就是 JavaScript 函数。
你同时还可以使用 ES6 的 class 来定义组件:
1 | class Welcome extends React.Component { |
上述两个组件在 React 里是等效的
自定义函数组件
React 元素也可以是用户自定义的组件:
1 | const element = <Welcome name="Sara" />; |
当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)转换为单个对象传递给组件,这个对象被称之为 “props”。
例如,这段代码会在页面上渲染 “Hello, Sara”:
1 | function Welcome(props) { |
注意: 组件名称必须以大写字母开头,React 会将以小写字母开头的组件视为原生 DOM 标签
所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。–类似于Vue的单向数据流,子组件不能修改父组件的传值,只能通过触发父组件的事件进行修改
所以我们只能修改组件内部的数据state,它 允许 React 组件随用户操作、网络响应或者其他变化而动态更改输出内容。 —–对比Vue的data和props
正确使用state
不要直接修改state—使用setState({})
- 构造函数是唯一可以给
this.state赋值的地方
- 构造函数是唯一可以给
state的更新可能是异步的
出于性能考虑,React 可能会把多个
setState()调用合并成一个调用因为
this.props和this.state可能会异步更新,所以你不要依赖他们的值来更新下一个状态。1
2
3
4
5
6
7
8
9// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
要解决这个问题,可以让 setState() 接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数:
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
state的更新会被合并
- 当你调用
setState()的时候,React 会把你提供的对象合并到当前的 state - 这就意味着:当你的state对象里面有多个值时,你多次调用setState({someKeys:xx})这里的对象合并是浅合并,setState方法保留了其他未被重置的属性,但是完全替换了someKyes
- 当你调用
将函数组件转换为class组件
———–需要注意的是,如果是通过compoent={}的形式,需要在constructor(props)进行传递
创建一个同名的 ES6 class,并且继承于
React.Component。添加一个空的
render()方法。将函数体移动到
render()方法之中。在
render()方法中使用this.props替换props。删除剩余的空函数声明
1
2
3
4
5
6
7
8// React.Component 是使用 ES6 classes 方式定义 React 组件的基类
export default class Some extends React.Component{
render() {
return (
<div>do some thing</div>
)
}
}———————通过以下方式将
props传递到父类的构造函数中:1
2
3
4constructor(props) {
super(props);
this.state = {date: new Date()};
}
事件处理
- React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
- 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。—使用表达式
一般情况下,传入没有调用的函数都会丢失this指向,解决办法是使用Function.prototype.bind()或者是使用箭头函数,亦或者是class fields进行解决
函数传入参数
在循环中,通常我们会为事件处理函数传递额外的参数。例如,若 id 是你要删除那一行的 ID,以下两种方式都可以向事件处理函数传递参数:
1 | <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> |
循环渲染需要带key
React 支持 key 属性。当子元素拥有 key 时,React 使用 key 来匹配原有树上的子元素以及最新树上的子元素
Vue的key属性也是做同样的事情,进行diffing算法运算
react.PureComponet
React.PureComponent 中的 shouldComponentUpdate() 将跳过所有子组件树的 prop 更新。因此,请确保所有子组件也都是“纯”的组件。
需要注意的小细节
- autoFocus一定要配合tabIndexReact
- 来使用
- constructor要配置super使用
- 渲染的时候要使用标签的形式进行渲染
- 在组件内部的dom元素中添加事件
组件渲染时的this问题
react 在render({this.state.xx})拿值是可以,但是在执行函数的时候却为undefined的原因?
—因为js是单线程事件型语言,当遇到函数或者定时器等异步操作时,会先向下执行,等事件触发,或者有空闲的时候再执行异步操作–那个时候,上下文已经丢失,所以this执行就已经丢失了
———–办法就是,
- 在dom渲染的时候,手动绑定上下文{this.事件名.bind(this)}
- 使用() => {利用箭头函数的特性绑定this}
组件的基本生命周期
以类定义的组件,都有一样的生命周期
- constructor() {}
- componentWillMount() {} //加载前,可以进行拿取数据
- render() {}
- componentDidMount() {} //页面加载完成
- if(进行更新state)————–
- componentWillUpdate() {} // 可以进行数据的验证
- render()
- compoentDidUpdate() //更新完成
有一个this.forceUpdate() –强制更新DOM
shouldCompoentUpdate() {return false} —不进行更新 — 控制componentWillUpdate的执行
————————————————————特殊的——————————————————
componentWillUnmount()—-:通过非React提供的方式注册的事件,通常需要在这个方法中注销事件,以及该组件中使用的计时器,也需要在这里清除!!!
setState的作用
- 可以用来更新数据
- 会自动地调用render()
父子组件中遇到的问题
父组件调用了render方法,则子组件必定会调用render方法。子组件调用render方法,则父组件不会调用render方法
父组件向子组件传值,是将父组件的数据或者方法作为子组件的属性值进行传递
子组件通过this.props.属性进行获取—(如果是通过函数的方式,则通过形参的方式进行获取)