一、基础入门体验
1、初体验
执行安装命令,主要包括react和react-dom两个包。 npm install react react-dom
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root"></div>
<!-- 1.引入js文件 -->
<script src="./node_modules/react/umd/react.development.js"></script>
<script src="./node_modules/react-dom/umd/react-dom.development.js"></script>
<script>
// 2 创建react元素
// 参数1:标签
// 参数2:属性
// 参数3及以后的参数:子节点
const title = React.createElement('h1', null, 'hello React')
// 3 渲染页面
// 参数1:react元素
// 参数2:容器挂载点
ReactDOM.render(title, document.querySelector('#root'))
</script>
</body>
</html>
2、raect脚手架
执行命令
npx create-react-app <项目名>
// 1 引入包
import React from 'react'
import ReactDOM from 'react-dom'
// 2 创建react元素
const title = React.createElement('h1', null, 'hello react 脚手架!!')
// 3 渲染react元素
ReactDOM.render(title, document.getElementById('root'))
3、JSX初体验
- 3.1 createElement()的问题
- 繁琐不简洁,不够优雅
- 不够直观,很难一言识别出所描述的结构
- 3.2 JSX
- JSX是JavaScript XML的简写,表示在javascript代码中书写XML(HTML)格式的代码
- 优势:声明式语法更加直观,与HTML结构相同,降低了学习成本、提高了开发效率
- 3.3 注意点
- React元素的属性名使用驼峰命名法
- 特殊属性名:class->
className、for->htmlFor、tabindex->tabIndex - 没有子节点的React元素可以用
/>结束 - 建议:使用
小括号包裹JSX,从而避免JS中的自动插入分好陷阱
import React from 'react'
import ReactDOM from 'react-dom'
// 1 创建react元素
const title = (
<h1 className="title">
hello JSX
<span />
</h1>
)
// 2 渲染react元素
ReactDOM.render(title, document.getElementById('root'))
4、在JSX中使用javascript表达式
语法:
{ javascript表达式 }
import React from 'react'
import ReactDOM from 'react-dom'
const name = 'yusong'
const age = 26
const title = (
<h1>
my name is
<span> { name }</span>
<span> age:{ age }</span>
</h1>
)
ReactDOM.render(title, document.getElementById('root'))
5、JSX条件渲染
条件渲染:根据条件渲染特定的JSX结构
可以使用
if-else或者三元表达式或者逻辑与运算符来实现
import React from 'react'
import ReactDOM from 'react-dom'
const isLoading = true
// 1、if-else
const loadData = () => {
if (isLoading) {
return <div>加载中。。。</div>
}
return <div>加载完毕!</div>
}
// 2、三元表达式
const loadData1 = () => {
return isLoading ? (<div>加载中1。。。</div>) : (<div>加载完毕1!</div>)
}
// 3、逻辑与运算符
const loadData2 = () => {
return isLoading && (<div>加载中2。。。</div>)
}
const title = (
<h1>
{loadData()}
{loadData1()}
{loadData2()}
</h1>
)
ReactDOM.render(title, document.getElementById('root'))
6、JSX列表渲染
- 如果要渲染一组数据,应该使用数组的map()方法
- 注意:渲染列表时应该添加key属性,
key的值要确保唯一性- 原则:map()遍历谁,就给谁添加key属性
- 注意:与vue一样,尽量避免使用索引值作为key
import React from 'react'
import ReactDOM from 'react-dom'
const songs = [
{id: 1, name: '奇迹再现'},
{id: 2, name: '不见就'},
{id: 3, name: '好不容易'}
]
const list = (
<ul>
{songs.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
)
ReactDOM.render(list, document.getElementById('root'))
7、JSX的样式处理
- 行内样式(style)
// 注意不是vue中的双大括号,是一个对象
<h1 style={{fontSize: '20px', color: 'red', backgroundColor: 'skyblue'}}>
style
</h1>
- 类名(className(推荐))
<h1 className="title">
style
</h1>
8、小结
- React完全使用js语言本身的能力来编写UI,而不是通过造轮子的方式来增强HTML能力。
二、 React组件
1、组件的介绍
- 特点:可复用、独立、可组合
2、组件的两种创建方式
使用函数创建组件
- 函数组件:使用JS函数(或者箭头函数)创建的组件
- 为了和普通函数做区分,react的函数组件做了以下约定
- 约定1:函数名称必须以
大写字母开头 - 约定2:组件名称必须以
大写字母开头,React以此来区分组件和普通的React元素 - 约定3:函数组件
必须有返回值,表示该组件的结构。如果返回值为null,则表示不渲染内容
- 约定1:函数名称必须以
- 渲染函数组件:用定义的函数名称直接作为组件的标签名称即可
- 组件标签既可以是单标签也可以是双标签
// 函数组件
// function SayHi() {
// return (
// <div>hi,function component</div>
// )
// }
// 箭头函数
const SayHi = () => <div>hi,箭头函数</div>
ReactDOM.render(<SayHi />, document.getElementById('root'))
使用类创建组件
- 类组件:使用ES6的class创建的组件
- 为了和普通的类做区分,react对类组件做了以下约定
- 约定1:类名称必须以
大写字母开头 - 约定2:类组件必须继承
React.component父类 - 约定3:类组件必须提供
render()方法 - 约定4:render()方法
必须有返回值,返回值表示该组件的结构
- 约定1:类名称必须以
// 类组件
class SayHi extends React.Component {
render() {
return (
<div>hi, class component</div>
)
}
}
ReactDOM.render(<SayHi />, document.getElementById('root'))
抽离为独立的JS文件
- 创建HelloWorld.js
- 在HelloWord.js中导入React
- 创建组件(函数或者类)
- 在HelloWorld.js组件中导出该组件
- 在index.js中导入HelloWorld组件
- 渲染组件
// HelloWorld.js
import React from 'react'
class HelloWorld extends React.Component {
render() {
return (
<div>hello, world</div>
)
}
}
// 导出
export default HelloWorld
// index.js
// 导入
import HelloWorld from './HelloWorld'
// 渲染
ReactDOM.render(<HelloWorld />, document.getElementById('root'))
3、React事件处理
事件绑定
- React事件绑定语法与DOM事件绑定语法相似
- 语法:
on+时间名称={事件处理程序},比如:onClick={() => {}} - 注意点:
React事件采用驼峰命名法,比如:onMouseEnter,onKeyUp
// 类组件
class App extends React.Component {
handleClick() {
console.log('单击事件触发了')
}
render() {
return (
<button onClick={this.handleClick}>click</button>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
// 函数组件
function FunctionComponent() {
function handleClick() {
console.log('funciton component click trigger');
}
return (
// 不需要this
<button onClick={handleClick}>click function component</button>
)
}
ReactDOM.render(<FunctionComponent />, document.getElementById('root'))
事件对象
- 可以通过
事件处理程序的参数获取事件对象 - React中的事件对象叫做:合成事件对象
- 合成事件:兼容所有浏览器,react内部帮我们封装处理了兼容性问题
class App extends React.Component {
handleClick(e) {
console.log('单击事件触发了')
// 阻止事件默认行为
e.preventDefault()
}
render() {
return (
<a href="https://www.baidu.com/" onClick={this.handleClick}>click</a>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
4、有状态组件和无状态组件
- 函数组件又叫做
无状态组件,类组件又叫做有状态组件 - 状态(state)即
数据 - 函数组件没有自己的状态,
只负责数据的展示(静态) - 类组件有自己的状态,
负责更新UI,让页面动起来
5、组件中的state和setState()
state的基本使用
- 状态(state)即数据,是组件内部的
私有数据,只能在组件内部使用 state的值是对象,表示一个组件中可以有多个数据- 通过
this.state来获取状态
class App extends React.Component {
constructor() {
super()
// 初始化状态
this.state = {
count: 0
}
}
// 简化语法初始化state
// state = {
// count: 10
// }
render() {
return (
<div>state: { this.state.count }</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
setState()修改状态
- 语法:this.setState({需要修改的数据})
- 注意:
不要直接通过this.state的值来修改数据 - setState()的作用
- 修改state数据
- 更新UI
- 通过数据驱动视图
class App extends React.Component {
constructor() {
super()
// 初始化状态
this.state = {
count: 0
}
}
// 简化语法初始化state
// state = {
// count: 10
// }
render() {
return (
<div>
<div>state: { this.state.count }</div>
{/* 点击事件 */}
<button onClick={() => {
this.setState({
count: this.state.count + 1
})
}}>+1</button>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
6、事件绑定this指向
箭头函数
利用箭头函数自身不绑定this的特点
class App extends React.Component {
constructor() {
super()
// 初始化状态
this.state = {
count: 0
}
}
handleClick() {
this.setState({
count: this.state.count + 1
})
}
render() {
return (
<div>
<div>state: { this.state.count }</div>
{/* 用箭头函数包裹,箭头函数中的this指向外部环境,此处为render()的this指向 */}
<button onClick={() => { this.handleClick() }}>+1</button>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
Function.prototype.bind()
通过ES5中的bind方法,将事件处理程序中的this与组件实例绑定到一起
class App extends React.Component {
constructor() {
super()
// 这里通过bind()处理一下
this.handleClick = this.handleClick.bind(this)
// 初始化状态
this.state = {
count: 0
}
}
handleClick() {
this.setState({
count: this.state.count + 1
})
}
render() {
return (
<div>
<div>state: { this.state.count }</div>
<button onClick={ this.handleClick }>+1</button>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
class的实例方法
- 利用箭头函数形式的class实例方法
class App extends React.Component {
constructor() {
super()
// 初始化状态
this.state = {
count: 0
}
}
// 定义为箭头函数
handleClick = () => {
this.setState({
count: this.state.count + 1
})
}
render() {
return (
<div>
<div>state: { this.state.count }</div>
<button onClick={ this.handleClick }>+1</button>
</div>
)
}
}
7、表单处理
受控组件
- 定义:其值受到了React控制的表单元素
- HTML中的表单元素是可输入的,也就是有自己的可变状态
- React中的可变状态通常保存在state中,并且只能通过setState()来修改
- React将state与表单表单元素值value绑定到一起,由state的值来控制表单元素的值
<input type="text" value={this.state.txt} />
使用步骤
- 在state中添加一个状态,作为表单元素的value值(控制表单元素值的来源)
- 给表单元素绑定change事件,将表单元素的值设置为state的值(控制表单元素的值的变化)
class App extends React.Component {
constructor() {
super()
// 初始化状态
this.state = {
txt: '',
content: '',
selectCont: 'sz',
isChecked: false
}
}
// 处理文本框的change
handleChange = e => {
this.setState({
txt: e.target.value
})
}
// 处理文本域的change
handleContent = e => {
this.setState({
content: e.target.value
})
}
// 处理下拉框的change
handleSelectChange = e => {
this.setState({
selectCont: e.target.value
})
}
// 处理复选框的change
handleCheckChange = e => {
this.setState({
isChecked: e.target.checked
})
}
render() {
return (
<div>
{/* 文本框 */}
<input type="text" value={this.state.txt} onChange={this.handleChange} />
<br />
{/* 文本域 */}
<textarea value={this.state.content} onChange={this.handleContent}></textarea>
<br />
{/* 下拉框 */}
<select value={this.state.selectCont} onChange={this.handleSelectChange}>
<option value="zs">深圳</option>
<option value="gz">广州</option>
<option value="dg">东莞</option>
</select>
<br />
{/* 复选框 */}
<input type="checkbox" checked={this.state.isChecked} onChange={this.handleCheckChange}></input>
</div>
)
}
}
- 代码优化
- 给表单元素添加name属性,名称与state相同,以此来实现动态修改state的不同字段
- 根据表单元素获取对应的值,比如checkbox是checked属性
- 在change方法中,通过[name]来实现动态修改state的不同字段
class App extends React.Component {
constructor() {
super()
// 初始化状态
this.state = {
txt: '',
content: '',
selectCont: 'sz',
isChecked: false
}
}
// 处理文本域的change
handleChange = e => {
const target = e.target
// 获取name属性
const name = target.name
// 判断是否为checkbox
const value = target.type === 'checkbox'
? target.checked
: target.value
this.setState({
[name]: value
})
}
render() {
return (
<div>
{/* 文本框 */}
<input type="text" name="txt" value={this.state.txt} onChange={this.handleChange} />
<br />
{/* 文本域 */}
<textarea name="content" value={this.state.content} onChange={this.handleChange}></textarea>
<br />
{/* 下拉框 */}
<select name="selectCont" value={this.state.selectCont} onChange={this.handleChange}>
<option value="zs">深圳</option>
<option value="gz">广州</option>
<option value="dg">东莞</option>
</select>
<br />
{/* 复选框 */}
<input type="checkbox" name="isChecked" checked={this.state.isChecked} onChange={this.handleChange}></input>
</div>
)
}
}
非受控组件(DOM方式)
- 借助ref,使用原生DOM方式来获取表单元素值
- ref的作用基本与vue中的ref一样(使用方法不一样):获取DOM或者组件
- 使用步骤:
- 调用React.createRef()方法创建一个ref对象
- 将创建好的ref对象绑定到DOM元素或者组件上
- 通过ref对象获取对应的值
class App extends React.Component {
constructor() {
super()
// 调用React.createRef()方法创建一个ref对象
this.txtRef = React.createRef()
}
getValue = () => {
// 通过ref对象获取对应的值
console.log(this.txtRef.current.value)
}
render() {
return (
<div>
{/* 将创建好的ref对象绑定到DOM元素或者组件上 */}
<input type="text" ref={this.txtRef} />
<button onClick={this.getValue}>获取input的值</button>
</div>
)
}
}