第一节: React简介
1, 什么是React
React 是一个用于构建用户界面的JavaScript库,
用户界面: HTML页面
React 主要用来写HTML页面,或构建Web应用
如果从MVC的角度来看,React不仅仅是视图层,也就是只负责视图的渲染,而并非提供了完整的M和C的功能。
React起源于Facebook的内部项目,与2013年5月开源
2, React的特点
1,声明式
const jsx = <div className = "app">
<h1>HellO React</h1>
</div>
2,基于组件
组件是react中最重要的内容
3,学习一次,随处使用
- 使用react可以开发web应用
- 使用react可以开发移动端原生应用(react-native)
- 使用react可以开发VR应用(react 360)
3, React的安装
安装命令npm install react react-dom
- react 包是核心, 提供创建元素,组件等功能
- react-dom 包提供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>
<script src="./node_modules/react/umd/react.development.js"></script>
<script src="./node_modules/react-dom/umd/react-dom.development.js"></script>
<script>
// 创建react 元素
const title = React.createElement('h1', null, 'Hello World')
// 渲染react 元素,并寻找挂载点
ReactDOM.render(title, document.getElementById('root'))
</script>
</body>
</html>
- React.createElement()说明
返回值: react元素
第一个参数: 要创建的react的元素名称
第二个参数: 该react元素的属性
第三个参数及其之后的参数: 该react元素的子节点
const title = React.createElement('h1', { title: '标题' }, 'Hello World')
- ReactDOM.render()说明
第一个参数: 要渲染的元素名称
第二个参数: DOM对象,用于指定渲染到页面中的位置
ReactDOM.render(title, document.getElementById('root'))
第二节:React 脚手架
1, React脚手架意义
1, 脚手架是开发,现代web应用的必备
2, 充分的利用webpack, babel, eslint等工具辅助项目开发
3, 零配置,而不是工具配置
2, React项目初始化
npx create-react-app my-app
cd my-app
yarn start
3, npx 命令介绍
npm v5.2.0引入的一条命令,目的是提升包内提供的命令行工具的使用体验。
原来:需要先安装脚手架包,现在无需安装脚手架包,可以直接使用这个包提供的命令。
推荐使用
npx create-react-app myProject
还有另外两种方式:
1, npm init react-app myProject
2, yarn create react-app myProject
4, JSX的基本使用
1, createElement()的问题
繁琐不简洁, 不直观,无法一眼看出所描述的结构,不优雅,用户体验不爽
React.createElement(
'div',
{className: 'shopping-list'},
React.createElement('h1', null, 'shopping-list'),
React.createElement(
'ul',
null,
React.createElemenet('li', null, 'Instagegram'),
React.createElemenet('li', null, 'WhatApp')
)
)
2, JSX 语法,等同于HTML语法
同一的页面结构,用JSX语法实现
<div className="shopping-list">
<h1>Shopping-list</h1>
<ul>
<li>Instagegram</li>
<li>WhatSapp></li>
</ul>
</div>
JSX就是JavaScript XML的简写,表示在JavaScript代码中写XML格式的代码,与HTML结构相同,降低了学习成本,提升了开发效率,JSX是React的核心内容
3,JSX的基本使用步骤
(1)使用JSX语法,创建react元素
const title = <h1>Hello JSX</h1>
(2) 使用ReactDOM.render()渲染react元素到页面中
ReactDOM.render(title, root)
4,为什么脚手架中可以使用JSX语法?
1, JSX 不是标准的ECMAScript语法,需要使用babel编译处理后,才能在浏览器中使用,
2, create-react-app脚手架中已经默认有该配置,无需手动配置
3, 编译JSX的语法包: @babel/preset-react
5, JSX 语法
注意点
1, React元素的属性名使用:驼峰命名法
2,特殊属性名:
class —> className
for—> htmlFor
tabindex—> tabIndex
3, 没有子节点的React 元素可以用 />结束
4,推荐: 使用小括号包裹JSX,从而避免JS中的自动插入分号陷阱
const div = (
<div>使用小括号包裹</div>
)
6, JSX 中使用JavaScript
条件渲染
1, 语法: { javaScript }
注意: 是单大括号, 不是双大括号
三元表达式
const isLoading = true
const loadData = () => {
return isLoading ? (<div>loading....</div>) : (<div>加载成功之后的数据</div>)
}
逻辑与运算符
const loadData = () => {
return isLoading && (<div>loading...</div>)
}
列表渲染
-
如果要渲染一组数据,应该使用数组的map()方法
-
注意: 渲染列表时,应该添加key属性,key属性的值要保证唯一
-
原则: map()遍历谁,就给谁添加key属性
const lista = (
<ul>
{
songs.map( item => {
return <li key={item.id}>{item.name}</li>
})
}
</ul>
)
JSX样式处理
(1) 行内样式 —style
<ul style={{color: 'red', background: 'skyblue'}}>
JSX的行内样式
</ul>
(2) 类名— className(推荐)
7, 总结
1, JSX 是React的核心内容
2, JSX表示在JS代码中写HTML结构,是React声明式的体现
3, 使用JSX配合嵌入的JS表达式,条件渲染,列表渲染,可以描述任意UI结构
4, 推荐使用className的方式给JSX添加样式
5, React 完全利用JS语言自身的能力来编写UI,而不是造轮子增强HTML功能
第三节:React 组件渲染
1, React 组件介绍
组件是react的一等公民,使用React就是在使用组件,组件表示的是页面中的部分功能,多个组件组合起来实现完整的页面功能
组件特点:可复用,独立,可组合
2, 组件的两种创建方式
-
函数组件
(1) 使用JS的函数创建的组件,或箭头函数
(2) 函数名称必须以大写字母开头
(3) 函数组件必须有返回值,表示该组件的结构
(4) 如果返回值为null, 表示不渲染任何东西
function Hello() {
return (
<div>这是函数组件</div>
)
}
const Say = () => {
return (
<div>箭头函数式组件</div>
)
}
函数式组件使用方式:
(1) 用函数名作为组件标签名
(2) 组件标签可以是单标签也可以是双标签
ReactDOM.render(<Hello />, root)
- 类组件 (1) React事件绑定语法与DOM事件语法相似
(2) 语法: on + 事件名称 = { 事件处理程序 } 比如: onClick = { () => {}}
(3) 注意:React 事件采用驼峰命名法,比如:onMouseEnter, onFocus
(4) 在函数组件中绑定事件,是没有this的
class Hello2 extends React.Component {
render() {
return (
<div>我是类组件</div>
)
}
}
ReactDOM.render(
<Hello2 />,
document.getElementById('root')
);
- 事件处理对象
(1)可以通过事件处理程序的参数获取到事件对象
class Hello2 extends React.Component {
handleClick(e) {
// 阻止a标签的默认行为
e.preventDefault();
console.log('a标签的点击事件触发了')
}
render() {
return (
<div>
<a href="http://www.baidu.com" onClick={this.handleClick}>我是类组件</a>
</div>
)
}
}
4, 有状态组件和无状态组件
- 函数组件又叫做无状态组件, 类组件又叫做有状态组件
- 状态(state)即数据
- 函数组件没有自己的状态,只负责数据展示(即静态页面)
- 类组件有自己的状态,负责更新UI,让页面动起来
5, 组件中的state 和 setState
(1) 状态即数据,是组件内部的私有数据,只能在组件内部使用
(2) state的值是对象,表示一个组件中更可以有多个数据
(3) 通过this.state来获取状态
import React from 'react'
class Hello2 extends React.Component {
state = {
count: 304
}
render() {
return (
<div>
<h1>{this.state.count}</h1>
</div>
)
}
}
(4)状态是可变的,可以通过setState() 修改状态,
(5)语法 this.setState( {要修改的数据} )
注意: 不要直接修改state中的值,这是错误的
this.setState({
count: this.state.count + 1
})
(6)setState的作用:
1,修改state,
2, 更新UI
思想:数据驱动视图
6, JSX中抽离事件处理程序
-
JSX中参杂了过多的JS逻辑代码,会显示非常混乱
-
推荐:将逻辑抽离到单独的方法中,保证JSX结构清晰
注意: 事件处理程序中的this的值为: undefined
-
我们希望: this指向组件实例,记住: render方法中的this即为组件实例
7, 解决事件绑定this指向
(1) 箭头函数 箭头函数自身不绑定this的特点,谁调用它,它就指向当前实例
onIncremnet() {
console.log('当前this的值', this)
this.setState({
count: this.state.count + 1
})
}
render() {
// 箭头函数中的this指向外部环境,此处为:render()方法,render方法中 // 的this就是组件实例
return (
<button onClick={()=> this.onIncrement()}></button>
)
}
(2) Function.prototype.bind() 利用ES5中的bind方法,将事件处理程序中的this与组件实例绑定到一起
class Hello2 extends React.Component {
constructor() {
super()
this.state = {
count: 304
}
this.onIncremnet = this.onIncremnet.bind(this)
}
onIncremnet() {
console.log('当前this的值', this)
this.setState({
count: this.state.count + 1
})
}
render() {
return (
<div>
<h1>{this.state.count}</h1>
<button onClick={ this.onIncremnet}>+1</button>
</div>
)
}
}
(3)在class实例的方法中,利用箭头函数 因为箭头函数中不绑定this, 所以箭头函数中的this指向的就是当前组件实例
class Hello2 extends React.Component {
constructor() {
super()
this.state = {
count: 304
}
}
onIncremnet =() => {
console.log('当前this的值', this)
this.setState({
count: this.state.count + 1
})
}
render() {
return (
<button onClick={ this.onIncremnet }>+1</button>
)
}
}
8, React中的表单处理
一,受控组件
- 1,HTML 中的表单元素是可输入的,也就是有自己的可变状态
- 2,React的可变状态保存在state中,并且只能通过setState()方法来修改
- 上面1,2两点相互冲突,都想通过自己的方式控制表单元素值,最好的办法就是:将React中的state与表单元素值value绑定到一起,有state的值来控制表单元素的值, 而改变state的值,只能通过setState方法
<input type="text" value={this.state.txt}
onChange = { e => this.setState({ txt: e.target.value})}
/>
DEMO 常用的表单获取值
import React from 'react'
class FormText extends React.Component {
constructor() {
super()
this.state = {
txt: '',
content: '',
city: 'bj',
isChecked: false
}
}
handleChange =(e) => {
this.setState({
txt: e.target.value
})
}
handleContent = (e) => {
this.setState({
content: e.target.value
})
}
handleCity = (e) => {
this.setState({
city: e.target.value
})
}
hanldeChecked = (e) => {
this.setState({
isChecked: e.target.checked
})
}
render() {
return (
<div>
<input type="text" value={this.state.txt} onChange={this.handleChange}></input>
<br />
<textarea value={this.state.content} onChange={this.handleContent}></textarea>
<br />
<select value={this.state.city} onChange={this.handleCity}>
<option value="sh">上海</option>
<option value="bj">北京</option>
<option value="sz">深圳</option>
<option value="gz">广州</option>
</select>
<br />
<input type="checkbox" checked= {this.state.isChecked} onChange=
{this.hanldeChecked}></input>
</div>
)
}
}
export default FormText
总结 1, 文本框,富文本框,下拉框,操作的都是value属性: e.target.value
2, 复选框操作的是 checked属性: e.target.checked
3,受控表单的优化
- (1)给表单元素添加name属性,名称与state相同
- (2)根据表单元素类型获取对应值
- (3)在change事件处理程序中通过[name]来修改对应的state
import React from 'react'
class FormText extends React.Component {
constructor() {
super()
this.state = {
txt: '',
content: '',
city: 'bj',
isChecked: false
}
}
handleForm =(e) => {
debugger
// 获取当前DOM对象
const target = e.target
// 根据类型获取值
const value = target.type === 'checkbox' ? target.checked : target.value
// 获取name
const name = target.name
this.setState({
[name]: value
})
}
render() {
return (
<div>
<input name="txt" type="text" value={this.state.txt} onChange=
{this.handleForm}></input>
<br />
<textarea name="content" value={this.state.content} onChange=
{this.handleForm}></textarea>
<br />
<select name="city" value={this.state.city} onChange={this.handleForm}>
<option value="sh">上海</option>
<option value="bj">北京</option>
<option value="sz">深圳</option>
<option value="gz">广州</option>
</select>
<br />
<input name="isChecked" type="checkbox" checked= {this.state.isChecked}
onChange={this.handleForm}></input>
</div>
)
}
}
export default FormText
二, 非受控组件 1, 非受控组件使用步骤:调用 React.createRef() 方法创建一个ref对象
construtor() {
super()
this.txtRef = React.createRef()
}
<input type="text" ref={this.txtRef} />
console.log(this.txtRef.current.value)
注意: 不要忘记current
3, 通过ref对象获取到文本框的值
2, 将创建好的ref对象添加到文本框中,相互绑定
9, 总结
React 组件基础
1, 组件的两种创建方式: 函数组件和类组件
2,函数组件又称无状态组件,负责静态结构展示
3,类组件又称有状态组件,负责更新UI,让页面动起来
4,绑定事件注意this的指向问题
5,推荐使用受控组件来处理表单
6,完全利用JS语言的能力创建组件,这就是React思想
发布评论的DEMO
import React from 'react'
class Form extends React.Component {
// 初始化状态
state = {
comments: [
{ id: 1, name: 'jack', content: '沙发'},
{ id: 2, name: 'rose', content: '板凳'},
{ id: 3, name: 'tom', content: '楼主好人'}
],
// 评论人
userName: '',
// 评论内容
userContent: ''
}
// 处理表单元素值
handleForm = (e) => {
const { name, value } = e.target
this.setState({
[name]: value
})
}
// 发布评论
handleClick = () => {
const { comments, userName, userContent } = this.state
if (userName.trim() === '' || userContent.trim() === '') {
return
}
const newComments = [{
id: Math.random(),
name: userName,
content: userContent
},...comments]
// 赋值,并清空文本框的值
this.setState({
comments: newComments,
userName: '',
userContent: ''
})
}
// 渲染评论列表
renderList() {
const { comments } = this.state
return comments.length === 0
?
( <div className="no-comment">暂无评论,快去评论吧</div>)
:
( <ul>
{ comments.map(item => {
return (
<li key={item.id}>
<h3>评论人:{item.name}</h3>
<span>评论内容:{item.content}</span>
</li>
)
})}
</ul>
)
}
render() {
const { userName, userContent } = this.state
return (
<div className="form">
<div>
<input className="user" type="text" placeholder="请输入评论人" value=
{userName} name="userName" onChange={this.handleForm}></input>
<br />
<textarea
className="content"
cols="30"
rows="10"
name="userContent"
value={userContent}
onChange={this.handleForm}
placeholder="请输入评论内容"
/>
<br />
<button onClick={this.handleClick}>发布评论</button>
</div>
{ /* 通过条件渲染决定渲染内容 */}
{
this.renderList()
}
</div>
)
}
}
export default Form;