React - The library for web and native user interfaces
React 入门
React 简介
React 是一个将数据渲染为 HTML 视图的开源 JavaScript 库,由 facebook 公司开发并开源
为什么要学习 React?
- 原生 JavaScript 操作 DOM 繁琐,效率低(DOM-API 操作 UI)
1 2 3
| document.getElementById('app') document.querySelector('#app') document.getElementsByTagName('span')
|
- 使用 JavaScript 直接操作 DOM,浏览器会进行大量的重绘重排
- 原生 JavaScript 没有组件化编码方案,代码复用率低
React 的特点
- 采用组件化模式,声明式编码,提高开发效率及组件复用率
- 在 React Native 中可以使用 React 语法进行移动端开发
- 使用虚拟DOM和优秀的Diffing 算法,尽量减少与真实 DOM 的交互
虚拟DOM
- 本质是
Object
类型的对象(一般对象)
- 虚拟 DOM 比较轻量级,真实 DOM 比较庞大,因为虚拟 DOM 是 React 内部在用,无需真实 DOM 上那么多属性
- 虚拟 DOM 最终会被 React 转换为真实 DOM,呈现在页面上
学习 React 前需要掌握的知识
- 判断 this 的指向
- Class
- ES6 语法规范
- npm 包管理器
- 原型,原型链
- 数组常用方法
- 模块化
React JSX
JSX 全称 JavaScript XML,是一种语法糖,可以在 JavaScript 中编写 HTML 代码
JSX 语法规则
- 定义虚拟 DOM 时不要写引号
- 标签中混入 JS 表达式时要用
{}
- 样式的类名指定不要用
class
,要用 className
- 内敛样式,要用双大括号的形式去写
- 虚拟 DOM 必须只有一个根标签
- 标签必须闭合,自闭合也可以
- 标签首字母
- 如果小写字母开头,则将该标签转为 HTML 中同名元素,若 HTML 中无该标签对应的同名元素,则报错
- 如果大写字母开头,React 就去渲染对应的组件,若组件没有定义,则报错
1 2
| style={{color:'skyblue',fontSize:'24px'}}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const data = ['A','B','C']
const VDOM = ( <div> <ul> { data.map((item,index)=>{ return <li key={index}>{item}</li> }) } </ul> </div> )
ReactDOM.render(VDOM,document.querySelector('.test'))
|
面向组件编程
渲染类组件标签的基本流程
- React 内部会创建组件实例对象
- 调用
render()
得到虚拟 DOM,并解析为真实 DOM
- 插入到指定的页面元素内部
组件的定义
函数式组件
1 2 3 4 5 6
| function MyComponent(props) { return <h1>Hello, {props.name}</h1>; }
ReactDOM.Render(<MyComponent name = "world" />,document.getElementById("div"));
|
类式组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class MyComponent extend React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } }
ReactDOM.Render(<MyComponent name = "world" />,document.getElementById("div"));
|
组件实例三大属性
state
state
React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致
React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)
1 2 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
| class Weather extends React.Component { constructor(props){ super(props); this.state = { isHot: false, wind: "微风", }; this.changeWeather = this.changeWeather.bind(this); } render() { const { isHot, wind } = this.state; return <h1 onClick={this.changeWeather}>今天天气很{isHot ? "炎热" : "凉爽"}, {wind}</h1>; }
changeWeather(){ const isHot = this.state.isHot; this.setState({ isHot: !isHot, }); } }
ReactDOM.Render(<Weather />,document.getElementById("div"));
|
在优化过程中遇到的问题
- 组件中的
render
方法中的 this
为组件实例对象
- 组件自定义方法中由于开启了严格模式,this 指向 undefined 如何解决
- 通过
bind
改变 this
指向
- 推荐采用箭头函数,箭头函数的 this 指向
state
数据不能直接修改或者更新
优化后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Weather extends React.Component { state = { isHot: false, wind: "微风", };
render() { const { isHot, wind } = this.state; return <h1 onClick={this.changeWeather}>今天天气很{isHot ? "炎热" : "凉爽"}, {wind}</h1>; }
changeWeather = ()=>{ const isHot = this.state.isHot; this.setState({ isHot: !isHot, }); } }
ReactDOM.Render(<Weather />,document.getElementById("div"));
|
props
与 state
不同,state
是组件自身的状态,而 props
则是外部传入的数据
类式组件中的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Person extends React.Component { render(){ return ( <ul> <li>{this.props.name}</li> <li>{this.props.age}</li> <li>{this.props.sex}</li> </ul> ) } }
ReactDOM.Render(<Person name="zhang" age="20" sex="male" />,document.getElementById("div"));
|
props
在使用的时候可以通过 this.props
来获取值类式组件的 props
:
- 通过在组件标签上传递值,在组件中就可以获取到所传递的值
- 在构造器里的
props
参数里可以获取到 props
- 可以分别设置
propTypes
和 defaultProps
两个属性来分别操作 props
的规范和默认值,两者都是直接添加在类式组件的原型对象上的(所以需要添加 static
)
- 同时可以通过
...
运算符来简化
1 2 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
| class Person extends React.Component { static propTypes = { name:PropTypes.string.isRequired, age:PropTypes.number, sex:PropTypes.string, }
static defaultProps = { age: 18, sex: 'male', }
render(){ return ( <ul> <li>{this.props.name}</li> <li>{this.props.age}</li> <li>{this.props.sex}</li> </ul> ) } }
const p = {name="zhang",age="20",sex="male"} ReactDOM.Render(<Person {...p} />,document.getElementById("div"));
|
函数式组件中的使用
1 2 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
| function Person (props) { render(){ const {name,age,sex} = props return ( <ul> <li>{name}</li> <li>{age}</li> <li>{sex}</li> </ul> ) } Person.propTypes = { name:PropTypes.string.isRequired, age:PropTypes.number, sex:PropTypes.string, }
Person.defaultProps = { age: 18, sex: 'male', } }
ReactDOM.Render(<Person name="zhang" sex="male", age={20} />,document.getElementById("div"));
|
refs
Refs
提供了一种方式,允许我们访问 DOM 节点或在 render
方法中创建的 React 元素
refs
共有3种操作 refs
的方法:
React.createRef()
创建 ref
容器
- 回调函数形式
- 字符串形式(已弃用)
1 2 3 4 5 6 7 8 9
| <input ref="var1" />
<input ref={currentNode => this.var1 = currentNode } />
var1 = React.createRef() <input ref={this.var1} />
|
回调形式的refs
组件实例的 ref
属性传递一个回调函数 c => this.input1 = c
(箭头函数简写),这样会在实例的属性中存储对 DOM 节点的引用,使用时可通过 this.input1 来使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Demo extends React.Component {
showData = ()=>{ const { input1 } = this alert(input1.value) }
render(){ return ( <div> <input ref={currentNode => this.input1 = currentNode } type="text" placeholder="点击按钮提示数据"/> <button onClick={this.showData}>点我提示数据</button> </div> ) } }
|
createRef形式的refs
React 给我们提供了一个相应的 API,它会自动的将该 DOM 元素放入实例对象中,推荐这种方式,但需要注意的是:一个节点创建一个容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Demo extends React.Component { myRef = React.createRef();
showData = ()=>{ console.log(this.myRef.current.value); }
render(){ return ( <div> <input ref={this.myRef} type="text" placeholder="点击按钮提示数据" /> <button onClick={this.showData}>点我提示数据</button> </div> ) } }
|
事件处理
事件处理
- 通过
onXxx
属性指定事件处理函数(注意大小写)
- React 使用的是自定义(合成)事件,而不是使用原生 DOM 事件,这是为了更好的兼容性
- React 中的事件是通过事件委托方式处理的(委托给组件最外层的元素),这是为了高效
- 通过
event.target
得到发生事件的 DOM 元素对象,不要过度使用 refs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Demo extends React.Component { myRef = React.createRef(); myRef2 = React.createRef();
showData = ()=>{ console.log(this.myRef.current.value); }
showData2 = (event)=>{ alert(event.target.value) }
render(){ return ( <div> <input ref={this.myRef} type="text" placeholder="点击按钮提示数据" /> <button onClick={this.showData}>点我提示数据</button> <input onBlur={this.showData2} type="text" placeholder="失去焦点提示数据" /> </div> ) } }
|
发生事件的元素正好是需要操作的元素,就可以避免使用 Refs
表单的组件分类
受控组件
非受控组件
组件声明周期
React-Router
PubSub
Ant-Design
参考