学习目的
熟练使用 React,并能运用 React 做一个项目,了解 React 开发。
学习技巧,用 学过的相似的知识技术 与 新知识 相对比,方便记忆,比如 拿 Vue 和 React 相对比,方便记忆与理解。
React 介绍
React是 Facebook 开源的一个js库,一个用于动态构建用户界面的js库。
React特点
虚拟DOM: React也是以数据驱动的,每次数据变化React都会扫码整个虚拟DOM树,自动计算与上次虚拟DOM的差异变化,然后针对需要变化的部分进行实际的浏览器DOM更新。
组件化: React可以从功能角度横向划分,将UI分解成不同组件,各组件都独立封装,整个UI是由一个个小组件构成的一个大组件,每个组件只关系自身的逻辑,彼此独立。
单项数据流:React设计者认为数据双向绑定虽然便捷,但在复杂场景下副作用也是很明显,所以React更倾向于单向的数据流动-从父节点传递到子节点。(使用ReactLink也可以实现双向绑定,但不建议使用)
Hello world 开场
JSX 语法(JavaScript XML)
JSX: react 定义的一种类似于XML的JS扩展语法: XML+JS;就是在js 中写HTML代码。
作用: 用来创建react虚拟DOM(元素)对象。
例如:var demo = <h1> Hello JSX! </h1>;
这种标签语法既 不是字符串 也 不是HTML,它最终产生的就是一个JS对象,它可以在JS中 写 HTML。
你可以用 花括号 把任意的 JS代码 嵌入到 JSX 中!!!!!!!!!!!
基本语法规则
* 遇到 < 开头的代码, 以标签的语法解析: html同名标签转换为html同名元素, 其它标签需要特别解析 ; 如果是空标签,应该像 XML 一样,使用 />立即闭合它:<img src='' />
* 遇到以 { 开头的代码,以JS的语法解析: 标签中的js代码必须用 { } 包含。
* 注意 !!!!!!!!!!!
* 标签必须有结束
* 标签的class属性必须改为className属性
* 标签的style属性值必须为: {{color:'red', width:12}}
组件(Components)和 属性
自定义组件(主要有2中形式定义)
注意:
1). 返回的组件类必须首字母大写
2). 嵌套的组件,虚拟DOM元素必须只有一个根元素
3). 虚拟DOM元素必须有结束标签 /
组件三大属性(props,refs,state)
①props属性(只读)
也可以写成
1. 每个组件对象都会有props(properties的简写)属性
2. 组件标签的所有属性都保存在props中
3. 内部读取某个属性值: this.props.属性名称
4. 作用: 通过标签属性从组件外向组件内传递数据(只读),我们不应该修改props的值!!!!
5. 对props中的属性值进行 类型限制 和 必要性限制,比如:
Person.propTypes = {
name:PropTypes.string.isRequired,
age: PropTypes.number.isRequired
}
6. 扩展属性: 将对象的所有属性通过props传递
7. 默认属性值
Person.defaultProps = {
name: 'Lily'
};
②refs属性(和 Vue 的refs 基本相同)
1). 组件内的标签都可以定义ref 属性来标识自己
2). 在组件中可以通过this.refs.refName来得到对应的真实DOM对象
3). 作用: 用于操作指定的ref属性的dom元素对象(表单标签居多)
*<input ref='username'/>
* this.refs.username //返回input对象
事件处理
1). 通过onXxx属性指定组件的事件处理函数(注意大小写,小驼峰命名法)
* React使用的是自定义(合成)事件, 而不是使用的DOM事件
* React中的事件是通过委托方式处理的(委托给组件最外层的元素)
2). 通过event.target得到发生事件的DOM元素对象
<input onFocus={this.handleClick}/.>
handleFocus(event) {
event.target //返回input对象
}
注意 !!!!!!!!
1). 组件内置的方法中的this为组件对象
2). 在组件中自定义的方法中的this为null
* 强制绑定this(在construtor中绑定)
* 箭头函数(ES6模块化编码时才能使用)
③ state 属性(和 Vue 的data 相似)
state 是 react 组件的初始数据
初始化状态:
constructor (props) {
super(props);
this.state = {
stateProp1 : value1,
stateProp2 : value2
};
}
读取数据状态值
this.state.statePropertyName
更新状态---->组件界面更新(不能使用this.state.statePropertyName = XXX;来设置值)
this.setState({
stateProp1 : value1,
stateProp2 : value2
})
实现一个双向绑定的组件
* React是单向数据流
* 需要通过onChange监听手动实现,更改state的值
state 案例 TodoList
React 生命周期
1).组件的三个生命周期状态:
* Mount:将虚拟DOM 插入真实 DOM(挂载)
* Update:被重新渲染(更新)
* Unmount:将虚拟DOM 移出真实 DOM(卸载)
2). React 为每个状态都提供了两种勾子(hook)函数,will 函数在进入状态之前调用,did 函数在进入状态之后调用
* componentWillMount( )
* componentDidMount( ) : 已插入真实DOM, 在 render 之后才会执行
* componentWillUpdate(object nextProps, object nextState)
* componentDidUpdate(object prevProps, object prevState)
* componentWillUnmount( )
3).生命周期流程:
①. 第一次初始化渲染显示: render( )
* constructor( ): 创建对象初始化state
* componentWillMount( ) : 将要插入回调
* render( ) : 用于插入虚拟DOM回调
* componentDidMount( ) : 已经插入回调
②. 每次更新state: this.setSate( )
* componentWillUpdate( ) : 将要更新回调
* render( ) : 更新(重新渲染)
* componentDidUpdate( ) : 已经更新回调
③. 删除组件
* ReactDOM.unmountComponentAtNode(document.getElementById('example')) : 移除组件
* componentWillUnmount() : 组件将要被移除回调
注意:
* 一般会在componentDidMount()中: 开启监听, 发送ajax请求
* 可以在componentWillUnmount()做一些收尾工作: 停止监听
条件渲染
React 中的条件渲染 和 Vue 中的 v-if = '' 相比,麻烦很多。
React 中的条件渲染就和在 JavaScript 中的条件语句一样。使用 JavaScript 操作符如 if 或者 条件操作符(如三元表达式,switch) 来创建渲染当前状态的元素,并且让 React 更新匹配的 UI 。
使用逻辑 && 操作符的内联 if 用法
它可以正常运行,因为在 JavaScript 中, true && expression 总是会评估为 expression ,而 false && expression 总是执行为 false 。因此,如果条件为 true ,则 && 后面的元素将显示在输出中。 如果是 false,React 将会忽略并跳过它。
就相当于 JavaScript中的操作符运算
还可以使用三元表达式 例如:
The user is <b> { isLoggedIn ? 'currently' : 'not' } </b> logged in.
列表(Lists) 和 键(Keys)
React 中的循环与 Vue 中的 v-for=' ' 相比 也比较复杂,但是它们都要在循环的元素标签上 加上 唯一的 key 值。
和 Vue 一样,键(Keys) 帮助 React 标识哪个项被修改、添加或者移除了。数组中的每一个元素都应该有一个唯一不变的键(Keys)来标识。不要用index !! 不要用index !! 不要用index !!
在React 中 使用 map()函数来遍历/ 循环数组。
受控组件
在 HTML 中,表单元素如 <input>,<textarea>和 <select>表单元素通常保持自己的状态,并根据用户输入进行更新。在 React 中,可变状态一般保存在组件的 state(状态) 属性中,并且只能通过 setState() 更新。
我们可以通过使 React 的 state 成为 “单一数据源原则” 来结合这两个形式。然后渲染表单的 React 组件也可以控制在用户输入之后的行为。这种形式,其值由 React 控制的输入表单元素称为“受控组件”。
简单的理解就是:将input中的value绑定到state的React组件就是可控组件,反之则是不可控组件。
受控组件的优点
1. React是一个单向数据流,受控组件符合React单向数据流特性,即从state 流向 render输出的结果。
2. 受控组件可以自定义双向数据流组件。
3.数据存储在state中,便于访问和处理。
textare 标签 和 select 标签 的情况与 input 一样 ,都是将便签的 value 与 state 绑定。
React 的编程思想
① 将 UI 拆解到组件层次结构中
分析 UI设计图,拆分组件
但是你该如何拆分组件呢?其实只需要像拆分一个新方法或新对象一样的方式即可。一个常用的技巧是 单一职责原则,即一个组件理想情况下只处理一件事。如果一个组件持续膨胀,就应该将其拆分为多个更小的组件中。
② 用 React 构建一个静态版本
要构建你 app 的一个静态版本,用于渲染数据模型, 您将需要构建复用其他组件并使用 props传递数据的组件。props 是将数据从 父级组件 传递到 子级 的一种方式。如果你熟悉 state 的概念,在构建静态版本时 *不要使用 *state ** 。state 只用于交互,也就是说,数据可以随时被改变。由于这是一个静态版本 app,所以你并不需要使用 state 。
可以 自上而下(构建层次结构中顶端的组件开始) 或 自下而上(构建层次结构中底层的组件) 构建。在更简单的例子中,通常 自上而下 更容易,而在较大的项目中,自下而上,更有利于编写测试。
③ 确定 UI state(状态) 的最小(但完整)表示
要正确的构建应用程序,你首先需要考虑你的应用程序需要的可变 state(状态) 的最小集合。这里的关键是:不要重复你自己 (DRY,don’t repeat yourself)。找出你的应用程序所需 state(状态) 的绝对最小表示,并且可以以此计算出你所需的所有其他数据内容。例如,如果你正在构建一个 TODO 列表,只保留一个 TODO 元素数组即可;不需要为元素数量保留一个单独的 state(状态) 变量。相反,当你要渲染 TODO 计数时,只需要获取 TODO 数组的长度即可。
④ 确定 state(状态) 的位置
React 单向数据流在层级中 自上而下 进行。这样有可能不能立即判断出状态属于哪个组件。这常常是新手最难理解的一部分,试着按下面的步骤分析操作:
对于你应用中的每一个 state(状态) :
1).确定每个基于这个 state(状态) 渲染的组件。
2)找出公共父级组件(一个单独的组件,在组件层级中位于所有需要这个 state(状态) 的组件的上面)。
3)公共父级组件 或者 另一个更高级组件拥有这个 state(状态) 。
4)如果找不出一个拥有该 state(状态) 的合适组件,可以创建一个简单的新组件来保留这个 state(状态) ,并将其添加到公共父级组件的上层即可。
⑤ 添加反向数据流
目前,构建的应用已经具备了正确渲染 props(属性) 和 state(状态) 沿着层次结构向下传播的功能。现在是时候实现另一种数据流方式:层次结构中深层的 form(表单) 组件需要更新中的 state(状态) 。也就是将 input等 表单元素 中的value绑定到state ,我们可以使用 input 的 onChange 事件来接收通知,而且通过 传递的回调调用 setState(),然后应用被更新。