React 学习之路01
1. 概述:
React 的特点: 声明式、基于组件、学习一次,随处使用
2. 脚手架的使用:
- 脚手架是开发 现代 Web 应用的必备
- 充分利用 Webpack、Babel、ESLint 等工具辅助项目开发
- 零配置,无需手动配置繁琐的工具即可使用
- 关注业务,而不是工具配置
(1)使用 React 创建项目
// 1. 创建项目
npx create-react-app my-app
// or
npm init react-app my-app
// or
yarn create react-app my-app
// 2. 根据时提示 使用命令,进入项目文件夹
cd my-app
// 3.启动项目,在项目根目录执行命令,出现 React 图标说明脚手架运行成功
npm start
(2)在脚手架中使用 react
// 1. 导入 react 和 react-dom 两个包
import React from 'react'
import ReactDOM from 'react-dom'
// 2. 调用 React.createElement() 方法创建 react 元素
const h3 = react.createElement('h4', { className: 'title' }, '一杆梅子酒')
// 3. 调用 ReactDOM.render() 方法渲染 react 元素到页面中
ReactDOM.render(h4, document.getElementById('root'))
3. JSX 的基本使用
- 定义:JSX 是 JavaScript XML 的简写,表示在 JavaScript 代码中写 XML(HTML) 格式的代码
- 优势:声明式语法更加直观、与 HTML 结构相同,降低了学习成本、提升开发效率
- jsx 是 React 的核心内容之一 , 它不是标准的 ECMAScript 语法,它是 ECMAScript 的语法扩展
使用 JSX 语法创建 react 元素
// 导入 react
import React from 'react'
import ReactDOM from 'react-dom'
// 使用 JSX 语法创建 react 元素
const h4 = (
<h4 className="title">一杆梅子酒</h4>
)
// 将元素渲染到页面上
ReactDOM.render(h4, document.getElementById('root'))
(1)jsx 使用注意事项
// 1. React 元素的属性名使用驼峰命名法
// 2. 特殊属性名:class -> className、for -> htmlFor、tabindex -> tabIndex
const p = <p className="box">我在等风,也在等你呀哈</p>
// 3.没有子节点的 React 元素可以用 /> 结束
const p = <input value="Tom" />
// 4.推荐:使用小括号包裹 JSX ,从而避免 JS 中的自动插入分号陷阱, 必须有一个根元素
const p = (<div>
<p className="box">我在等风,也在等你呀哈</p>
<input value="Tom" />
</div>)
(2)在 jsx 中使用 JS 表达式
// 1. 数据存储在 JS 中
// 2. 语法:{ JavaScript表达式 }
// 3. 注意:语法中是单大括号,不是双大括号
// 导入 react
import React from 'react'
import ReactDOM from 'react-dom'
const name = '亚瑟'
const age = 18
const title = (
<div>{ name } -- { age }</div>
)
// 页面中显示 亚瑟--18
(3)JSX 中使用 JS 表达式注意事项
- 单大括号中可以使用任意的 JavaScript 表达式
- JSX 自身也是 JS 表达式
- 注意:JS 中的对象是一个例外,一般只会出现在 style 属性中
- 注意:不能在 {} 中出现语句(比如:if/for 等)
// 导入 react
import React from 'react'
import ReactDOM from 'react-dom'
// 声明一个函数
function handle() {
return 1
}
// jsx 创建的元素也是表达式
const span = <span>Tom</span>
// 2. 创建元素
const p = (
<div>
<p>{1 + 1}</p> // 2
<p>{2 > 1 ? '大于' : '小于'}</p> // 大于
<p>{handle()}</p> // 1
<p>{span}</p> // <span>Tom</span>
{/* 不能在 `{}` 中出现语句(比如:`if/for` 等) */}
{/* <p>{ if (true) {} }</p> */}
{/* `JS` 中的对象是一个例外,一般只会出现在 `style` 属性中 */}
{/* <p>{{ 1 }}</p> */}
</div>
)
(4) 条件渲染
- React 中的条件渲染和 JavaScript 中的一样
- 使用 JS 运算符 if/else 或 三元运算符 或 逻辑与运算符 来判断当前元素的状态,然后让 React 根据它们来更新 UI
// 完整代码
import React from 'react'
import ReactDOM from 'react-dom'
/*
条件渲染:
*/
const isLoading = false
// if/else
const loadData = () => {
if (isLoading) {
return <div>loading...</div>
}
return <div>数据加载完成,此处显示加载后的数据</div>
}
// 三元表达式:
const loadData = () => {
return isLoading ? (<div>loading...</div>) : (<div>数据加载完成</div>)
}
// 逻辑与运算符:
const loadData = () => {
return isLoading && (<div>loading...</div>)
}
const title = (
<h1>
条件渲染:
{loadData()}
</h1>
)
// 渲染react元素
ReactDOM.render(title, document.getElementById('root'))
(5)列表渲染
- 如果要渲染一组数据,应该使用数组的 map() 方法
- 注意:渲染列表时应该添加 key 属性,key 属性的值要保证唯一
- 原则:map() 遍历谁,就给谁添加 key 属性
- 注意:尽量避免使用索引号作为 key
import React from 'react'
import ReactDOM from 'react-dom'
// 歌曲列表:
const heros = [
{id: 1, name: '李知恩'},
{id: 2, name: '迪丽热巴'},
{id: 3, name: '周冬雨'},
]
const list = (
<ul>
{heros.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
)
// 渲染react元素
ReactDOM.render(list, document.getElementById('root'))
(6)jsx 样式的处理,最常用的两个方式是: 行内式 以及 类名 例如:
// style
<h1 style={{ color: 'red', backgroundColor: 'skyblue' }}>
JSX的样式处理
</h1>
// className
<h1 className="title">
JSX的样式处理
</h1>
大概 jsx 的基础语法就这些了,总结一下吧:
- JSX 是 React 的核心内容
- JSX 表示在 JS 代码中写 HTML 结构,是 React 声明式的体现
- 使用 JSX 配合嵌入的 JS 表达式、条件渲染、列表渲染,可以描述任意 UI 结构
- 推荐使用 className 的方式给 JSX 添加样式
- React 完全利用 JS 语言自身的能力来编写 UI,而不是造轮子增强 HTML 功能
4. React 中组件介绍
(1)特点:
- 组件是 React 的一等公民,使用 React 就是在用组件
- 组件表示页面中的部分功能
- 组合多个组件实现完整的页面功能
- 特点:可复用、独立、可组合
(2)创建 react 组件的两种方式
- 使用函数创建组件
- 使用类创建组件
使用函数创建组件
- 函数组件:使用 JS 的函数或者箭头函数创建的组件
- 约定1:函数名称必须以大写字母开头
- 约定2:函数组件必须有返回值,表示该组件的结构
- 如果返回值为 null,表示不渲染任何内容
import React from 'react'
import ReactDOM from 'react-dom'
// 创建函数组件
// 1. 函数名称首字母大写字母开头
function Hello() {
// 2. 函数组件必须有返回值
return (
<div>这是我的第一个函数组件</div>
)
}
// 不渲染结构:
// function Hello() {
// 函数内部如果不返回任何值,需要返回 null
// return null
// }
// 使用箭头函数创建组件:
// const Hello = () => <div>这是我的第一个函数组件</div>
ReactDOM.render(<Hello />,document.getElementById('root'))
使用函数组件总结:
- 使用JS中的函数创建的组件叫做:函数组件
- 函数组件必须有返回值
- 组件名称必须以大写字母开头, React 据此区分 组件 和 普通的React 元素
- 使用函数名作为组件标签名
使用类创建组件
类组件:使用 ES6 的 class 创建的组件
- 约定1:类名称也必须以大写字母开头
- 约定2:类组件应该继承 React.Component 父类,从而可以使用父类中提供的方法或属性
- 约定3:类组件必须提供 render() 方法
- 约定4:render() 方法必须有返回值,表示该组件的结构
import React from 'react'
import ReactDOM from 'react-dom'
// 创建类组件
// 1. 类组件名称以大写字母开头
// 2. 类组件继承自 React.Component
class Hello extends React.Component {
// 3. 类组件必须提供 render() 方法
render() {
// 4. render() 方法必须有返回值
return (
<div>这是我的第一个类组件</div>
)
}
}
// 渲染组件
ReactDOM.render(<Hello />, document.getElementById('root'))
React 事件处理
(1)事件绑定
- React事件绑定语法与 DOM 事件语法类似
- 语法: on + 事件名称 = {事件处理程序},例如: onClick = { () => {} }
- 注意: React 事件采取驼峰命名法,比如: onClick、onMouseEnter
- 注意: 在类组件和函数中调用函数的方式是不同的
- 在类组件中调用方法需要使用 this.方法
- 在函数组件中调用方法直接触发 方法 即可
// 类组件绑定事件:
import React from 'react'
export default class App extends React.Component {
handle() {
console.log('单击事件触发成功')
}
render() {
return (
// 在类组件中调用方法需要使用 `this.方法`
<button onClick={this.handle}>触发事件</button>
)
}
}
// 函数组件绑定事件:
import React from 'react'
function App() {
function handle () {
console.log('我是函数组件的方法')
}
return (
// 直接调用方法的名称即可
<button onClick={handle}>触发方法</button>
)
}
export default App
(2)事件对象
- 通过事件处理程序的参数获取到事件对象
- React 中的事件对象叫做: 合成事件(对象)
- 合并事件: 兼容所有浏览器,无需担心跨浏览器兼容性问题
import React from 'react'
export default class App extends React.Component {
handle(e) {
e.preventDefault()
console.log('单击事件触发成功')
}
render() {
return (
<a href="http://www.baidu.com" onClick={this.handle}>点我</a>
)
}
}
有状态组件和无状态组件
- 函数组件又叫做无状态组件,类组件又叫做有状态组件
- 所谓的状态实际上就是数据
- 函数组件没有自己的状态,只负责数据展示
- 类组件有自己的状态,负责更新 UI,让页面 “动起来”
- 也就是说有状态组件和无状态组件的区别就是有没有自己的私有数据,即能不能定义 state
state的基本使用
- 状态(state) 即数据;
- 状态是组件内部的私有数据,只能在组件内部使用
- state 的值是对象,表示一个组件中可以有多个数据
- 使用 this.state.xxx 获取 state 中的数据
初始化 state 的两种方式
- 在 constructor 内部声明 state
- 简化语法,和 render 方法同级声明 state 对象
// 第一种声明方式
import React from 'react'
export default class App extends React.Component {
// 在 constructor 内部声明 state
constructor () {
super()
this.state = {
name: '亚瑟'
}
}
render () {
return null
}
}
// 第二种声明方式 (推荐使用 因为简单)
import React from 'react'
export default class App extends React.Component {
// 简化语法
state = {
name: '百里玄策'
}
// 获取 state 中的数据
render () {
return <div>获取state 中的数据 : {this.state.name}</div>
}
}
使用 setState() 修改状态
- state 状态是可以变化的,即可以修改的
- 语法: this.setState({ 要修改的数据 })
- 注意: 不要直接修改 state 中的值,这种做法是错误的 !
- steState() 的作用:
- 修改 state 数据
- 更新 UI
- 使用 staState 修改数据,并驱动 UI 更新的做法,叫做 数据更新数据
这种方式是错误的使用方式:
// 演示错误的代码
export default class App extends React.Component {
state = {
age: 3
}
addHandle() {
this.setState({
age: this.state.age + 1
})
}
render() {
return (
<div>
<button onClick={this.addHandle}>更改数据</button>
<p>{this.state.age}</p>
</div>
)
}
}
- 原因: 事件处理程序中 this 的值为 undefined
- 正确的做法: this 指向组件实例(render方法中的this即为组件实例)
事件绑定 this 指向
解决以上问题, 改变 this 的指向
- 箭头函数
- Function.prototype.bind()
- class 的实例方法
(1) 箭头函数的方式
- 利用了箭头函数自身不绑定 this 的特点
- render() 方法中的 this 为组件实例,可以获取到 setState()
export default class App extends React.Component {
state = {
age: 3
}
addHandle() {
this.setState({
age: this.state.age + 1
})
}
render() {
return (
<div>
{/* 箭头函数的方式改变 this 执行 */}
<button onClick={() => this.addHandle()}>更改数据</button>
<p>{this.state.age}</p>
</div>
)
}
}
(2) Function.prototype.bind()
- 利用 ES5 中的 bind方法,将事件处理程序中的 this 与组件实例绑定到一起
- 这个方案是官方推荐的方案
export default class App extends React.Component {
constructor () {
super()
this.state = {
age: 3
}
// 利用ES5中的bind方法,将事件处理程序中的this与组件实例绑定到一起
this.addHandle = this.addHandle.bind(this)
}
addHandle() {
this.setState({
age: this.state.age + 1
})
}
render() {
return (
<div>
{/* 箭头函数的方式改变 this 执行 */}
<button onClick={this.addHandle}>更改数据</button>
<p>{this.state.age}</p>
</div>
)
}
}
(3) class 实例方法
- 利用箭头函数形式的 class 实例方法
- 注意:该语法是实验性语法,但是,由于 babel 的存在可以直接使用
- 这么多解决的方法,class 的实例方法比较友好一点
export default class App extends React.Component {
constructor () {
super()
this.state = {
age: 3
}
}
// 利用箭头函数形式的class实例方法
addHandle = () => {
this.setState({
age: this.state.age + 1
})
}
render() {
return (
<div>
<button onClick={this.addHandle}>更改数据</button>
<p>{this.state.age}</p>
</div>
)
}
}