目录
[1. JSX的基本使用](#1. JSX的基本使用)
[1.1 为什么用JSX](#1.1 为什么用JSX)
[1.2 JSX简介](#1.2 JSX简介)
[1.3 使用步骤](#1.3 使用步骤)
[1.4 脚手架中能用JSX](#1.4 脚手架中能用JSX)
[1.5 注意点](#1.5 注意点)
[2. 在JSX中使用JavaScript表达式](#2. 在JSX中使用JavaScript表达式)
[2.1 嵌入js表达式](#2.1 嵌入js表达式)
[2.2 注意点](#2.2 注意点)
[5.1 行内样式 style](#5.1 行内样式 style)
[5.2 类名 className](#5.2 类名 className)
[2.1 使用函数创建组件](#2.1 使用函数创建组件)
[2.2 使用类创建组件](#2.2 使用类创建组件)
[2.3 将组件抽离为单独的js文件](#2.3 将组件抽离为单独的js文件)
[4.1 state的基本使用](#4.1 state的基本使用)
[4.2 setState修改状态](#4.2 setState修改状态)
[4.3 从JSX中抽离事件处理程序](#4.3 从JSX中抽离事件处理程序)
TODO1
React概述
1.是用于构建用户界面的JavaScript库
2.特点: 声明式 基于组件 学习一次随处使用
①声明式 只需要描述UI看起来是什么样 react负责渲染并在数据变化时更新
②组件 表示页面中的部门内容 组合复用多个组件可以实现完整的页面功能 (最重要)
③学习一次,随处使用 web应用 移动端原生应用 虚拟现实应用均可使用
3.推荐使用脚手架使用react
React的使用
//引入react和react-dom两个js文件
<script src="./node_modules/react/umd/react.development.js"></script>
<script src="./node_modules/react-dom/umd/react-dom.development.js"></script>
//创建react元素
//参数一 元素名称 参数二 元素属性 参数三 元素的子节点
const title = React.createElement('h1',null,'hello react')
// const title = React.createElement(
// 'p',
// { title: '我是标题',id:'p1'},
// 'hello react'
// React.createElement('span',null,'我是span节点')
// )
//渲染react元素 (仅针对web开发)
//参数一 要渲染的react元素 参数二 挂载点-》页面中指定的位置
ReactDOM.render(title,document.getElementById('root'))
React脚手架的使用
全局安装脚手架和npx安装脚手架的区别
全局安装
npm start:执行开发模式,运行该项目
npm run build:执行生产模式,打包该项目
npm test:执行测试模式,测试该项目
npm run eject:将webpack相关文件暴露出来(React设置webpack文件隐藏
npx安装
npx create-react-app 是固定命令,create-react-app是React脚手架的名称
npx 命令会帮助我们临时安装create-react-app包,然后初始化项目完成之后会自自动删掉
不需要进行全局安装(但是我已经安装完了··
初始化项目
npx create-react-app my-app
启动项目
在项目的根目录下执行** 先cd项目
npm start
在脚手架中使用React
脚手架能够帮助我们自动刷新页面
//1.导入react和react-dom两个包(非script标签导入)使用es6中的模块化语法
import React from 'react'
import ReactDOM from 'react-dom'
//2. 调用React.createElement()方法创建react元素
const title = React.createElement('p',null,'hello react')
//3. 调用ReactDOM.render()方法渲染react元素到页面中
ReactDOM.render(title,document.getElementById('') //挂载点
脚手架文件介绍
JSX
- JSX的基本使用
1.1 为什么用JSX
React.createElement()过于繁琐不简洁 -》和用模板字符串一样
1.2 JSX简介
1.JavaScript XML 表示在JavaScript中写HTML格式的代码
2.声明式语法更加直观 开发效率高 学习成本低
3.是React的核心内容 完全利用js语言自身的能力来编写UI
1.3 使用步骤
//1.使用JSX语法创建 React元素
const title =<h1> hello jsx</h1>
//2.使用ReactDOM.render()方法渲染react元素到页面中
ReactDOM.render(title,root)
1.4 脚手架中能用JSX
1.JSX是ECMAScript的扩展
2.需要使用babel编译处理才能在浏览器环境中使用 (脚手架中已有相关配置)
3.编译JSX语法的包为:@babel/preset-react
1.5 注意点
1.元素的属性名用驼峰命名法
2.特殊属性名 class->className for->htmlFor tabindex->tabIndex
3.没有子节点的React元素可以用/>结束
<span>hello react</span> hello react</span>
4.使用()包裹JSX (结构清晰 避免JS自动插入分号陷阱)
const div=( <div>hello jsx</div> )
- 在JSX中使用JavaScript表达式
2.1 嵌入js表达式
1.数据存储在js中
2.语法:{JavaScript}表达式
const name ='cc' const div ={ <div> hello {name} </div> }
2.2 注意点
1.单大括号中可以使用任意的JavaScript表达式
2.JSX自身也是JavaScript表达式
const sayHi=() => 'Hi'
const title =(
<h1>可以使用任意的函数表达式</h1>
<span>{1}</span>
<span>{'a'}</span>
<span>{1+2}</span>
<span>{3>5?1:0}</span>
<span>{sayHi()}</span>
)
const h1=<h1>cc</h1>
const div=(
<div> JSX自身也是js表达式 {h1} </div>
)
3.js中的对象一般只会出现在style属性
4.{}中不能出现语句
3.JSX的条件渲染
1.场景:loading效果
2.条件渲染 根据条件渲染特定的jsx结构
3.可以使用if/else或三元运算符或逻辑与运算符实现
//if else
const loadData=() =>{
if(isLoading){
return <div>数据加载中 请稍后 </div>
}
return (
<div>数据加载完成,这里显示的是数据</div>
)
}
const div=(
<div>
{loadData()}
</div>
)
//三元表达式
const loadData =() =>{
return isLoading ?(<div>数据加载中</div>) :(<div>数据加载完成,这里显示的是数据</div>)
}
//逻辑与运算符 --适合要么展示 要么隐藏
const loadData=() =>{
return isLoading &&( <div> loading</div>)
}
const div=(
<div>
{loadData()}
</div>
)
4.JSX的列表渲染
1.要渲染一组数据 应该使用map()方法
2.渲染列表时要加key属性 key属性的值要保证唯一-id
3.map()遍历谁 就给谁加key属性
4.避免使用索引号(索引号会发生改变)
const targets =[
{id:1,name:'react基础'},
{id:2,name:'react进阶'},
{id:3,name:'git+移动端开发+模块化'},
]
const list =(
<ul>
{targets.map(item=> <li key={item.id>{item.name}</div>)}
</ul>
)
5.JSX的样式处理
5.1 行内样式 style
//看起来像双括号 但实际上不是 外侧的表示嵌入对象
<h1 style={{color:'red',backgroundColor: 'skyblue'}}>
jsx样式处理
</h1>
5.2 类名 className
<h1 className="title">
jsx样式处理
</h1>
//要注意引入css文件
import 'index.css'
TODO2
组件
1.组件介绍
- 使用react就是在使用组件
- 组件表示页面中的部分功能
- 组合多个租金按能实现完整的页面
- 特点:可复用、独立、可组合
2.组件的两种创建方式
2.1 使用函数创建组件
函数组件:使用js的函数(或箭头函数)创建的组件
//函数名称必须以大写字母开头
function Hello() {
return (
<div>函数组件是必须有返回值的,表示该组件的结构,返回值为null表示不渲染任何结构</div>
)
}
//渲染函数组件 -》用函数名作为组件标签名
//组件名要大写的原因是 react据此区分普通组件和 react元素
//组件标签名 可以是单标签 也可以是双标签
//箭头函数创建组件
const Hello =() => (<div>函数组件</div>)
ReactDOM.render(<Hello />,root)
2.2 使用类创建组件
类组件:使用ES6的class创建的组件
- 类名称也必须以大写字母开头
- 类组件应该继承 React.Component父类,从而可以使用父类提供的方法或属性
- 类组件必须提供render()方法
-
render()方法必须有返回值 表示该组件的结构
//类名必须用大写字母开头
//继承React.Component父类
class Hello extends React.Component{
//必须提供render()方法
render() {
//必须有返回值 表示该组件的结构
return (
类组件
)
}
}
ReactDOM.render(</Hello>,root)
2.3 将组件抽离为单独的js文件
每个组件放到单独的js文件中
- 创建Cc.js(组件的js文件)
- 在Cc.js中导入React
- 创建组件(函数或类)
- 在Cc.js中导出该组件
- 在index.js(要使用这个组件的文件)中导入组件
-
渲染组件
//Cc.js
import React from 'react'
class Cc extends React.Component{
render() {
return (啊啊啊啊)
}
}
//导出组件
export default Cc//index.js
//导入组件
import Cc from '路径'
//渲染导入的组件
ReactDOM.render(<Cc />, document.getElementById('root'))
事件处理
1.事件绑定
- 与DOM事件绑定语法类似
- on+事件名称={事件处理程序} //驼峰命名法
-
如果是类组件绑定 用this. 如果是函数组件绑定 直接写函数名字即可
//类创建
class App extends React.Component{
handleClick(){
console.log('类组件中的事件绑定')
}
render(){
return(
<button onClick={this.handleClick}> 点了会发生啥?</button>
)
}
}//函数
function App() {
function handleClick(){
console.log('函数组件中的事件绑定')
}
return(
<button onClick={handleClick}>点</button>
)
}//渲染组件
ReactDOM.render(<App />,document.getElementById('root'))
2.事件对象
通过事件处理程序的参数获取到事件对象
React中的事件对象叫合成事件(对象)
合成事件:兼容所有浏览器,无需担心跨浏览器兼容性问题(了解即可)
class App extends React.Component{
handleClick(e){
e.preventDefault()
}
render(){
return(
<a href="" onClick={this.handleClick}>我没加链接</a>
)
}
}
//渲染组件
ReactDOM.render(<App/>,document.getElementById('root'))
3.有状态组件和无状态组件
状态 state即数据
- 函数组件叫做无状态组件 只负责数据展示(静态)
- 类组件叫做有状态组件 负责更新UI (动态)
4.state和setState()
4.1 state的基本使用
- state是组件内部的私有数据,只能在组件内部使用
- state的值是对象 表示一个组件中可以有多个数据
如何使用state
class Cc extends React.Component {
//es6 class语法
constructor(){
super() //必须有 是es6的要求
//初始化state
this.state ={
count :0
}
}
//简洁版 实验性的public class fields语法
state = {
count :0
}
render(){
return (
<div>
有组件状态
</div>
)
}
}
①super()函数用于访问和调用一个对象上的父对象上的函数
②在构造函数中使用时,super关键字将单独出现,并且必须在使用this关键字之前 使用。
super关键字也可以调用父对象上的函数。
4.2 setState修改状态
- 状态可以改变
- this.setState({要修改的数据})
- 不要直接修改state中的值
-
setState() 作用 1.修改state 2.更新UI -》数据驱动视图
this.setState({
count:this.state.count + 1
})//错误的
this.state.count += 1
4.3 从JSX中抽离事件处理程序
如果JSX中有过多的js逻辑代码 会显得很混乱
将逻辑抽离到单独的方法中,保证结构的清晰
但是会出现事件处理程序中的this的值为undefined的情况
希望this指向组件实例(render方法中的this即为组件实例)
组件实例本质上就是一个状态集合(或一个对象)
this指向
1.箭头函数
①箭头函数自身不绑定this
②render方法中的this为组件实例,可以获取到setState()
class Cc extends React.Component{
onIncrement(){
this.setState({ })
}
render(){
//箭头函数中的this指向外部环境,此处为:render() 方法
return (
<button onClick={() => this.onIncrement()}></button>
)
}
}
2.Function.prototype.bind()
class Cc extends React.Component{
constructor() {
super()
this.onIncrement = this.onIncrement.bind(this)
}
//省略onIncrement
render(){
return (
<button onClick={this.onIncrement()}></button>
)
}
}
3.class的实例方法
①利用箭头函数形式的class实例方法
②该语法是实验性语法 但是由于babel的存在可以直接用(编译JSX的语法包)
class Cc extends React.Component{
onIncrement =() =>{
this.setState({...})
}
render(){
return (
<button onClick={this.onIncrement()}></button>
)
}
}
4.总结
推荐使用的顺序 class的实例方法>箭头函数>bind
表单处理
1.受控组件
推荐使用受控组件来处理表单
值受到React控制的表单元素
- HTML的表单元素是可输入的 有自己的可变状态
- React中的可变状态通常保存在State中,并且只能通过setState()方法获取
二者冲突 所以 React把state与表单元素值value绑定 由state的值来控制表单元素的值
//1.在state中添加一个状态 作为表单元素的value值(控制表单元素值的来源)
state={txt:''}
//2.给表单元素绑定change事件,将表单元素的值设置为state的值(控制表单元素值的变化)
<input type="text" value={this.state.txt}
onChange ={e => this.setState({ txt : e.target.value })}
/>
多表单元素优化步骤
1.给表单元素加name属性,名称与state相同
2.根据表单元素类型,获取对应的值
3.在change事件处理程序中,通过[name]修改对应的state
<input
type="text"
name="txt" //区分其他表单元素 名称与state相同
value={this.state.txt}
onChange={this.handleForm}
/>
//根据表单元素类型获取值
const value=target.type === 'checkbox'
?target.checked
:target.value
//根据name设置对应的state
this.setState({
//es6的属性表达式
[name]:value
})
2.非受控组件
1.借助ref 使用原生DONM方式来获取表单元素的值
ref的作用:获取DOM组件
2.使用步骤
①调用React.createRef()方法创建一个ref对象
②将创建好的ref对象添加到文本框中
③通过ref对象获取到文本框的值
3.大多数情况下 用受控组件
//1.调用
constructor() {
super()
this.txtRef = React.createRef()
}
//2.将ref添加到文本框
<input type="text" ref={this.txtRef} />
//3.通过ref对象获取到文本框的值
console.log{this.txtRef.current.value}
//实践
class App extends React.Component{
constructor() {
super()
this.txtRef = React.createRef()
}
//获取文本框的值
getTxt =() =>{
console.log('文本框的值为:', this.txtRef.current)
}
render(){
return(
<div>
<input type="text" ref={this.txtRef} />
<button onClick={this.getTxt}获取文本框的值</button>
</div>
)
}
}
完全利用js语言的能力创建组件,这是React的思想
TODO3
组件通讯
1.组件通讯的定义
因为组件时独立且封闭的单元,默认情况下,只能使用组件自己的数据,在组件化的过程中,我们要将完整的功能拆分为多个组件,这里需要共享一些数据,所以应该让组件与外界进行"通讯"
2.组件通讯的三种方式
2.1 父组件 ->子组件
①父组件提供要传递的state数据
②给子组件标签添加属性,值为state中的数据
③子组件通过props接收父组件传递的数据
2.2 子组件 ->父组件
思路:利用回调函数,父组件提供回调,子组件调用。将要传递的数据作为回调函数的参数。
①父组件提供一个回调函数(用于接收数据)
②将该函数作为属性的值,传递给子组件。
③子组件通过props调用回调函数。
④将子组件的数据作为参数传递给回调函数。
2.3兄弟组件
将共享状态提升到最近的公共父组件中,由公共父组件管理这个状态
思想:状态提升
公共父组件职责 1.提供共享状态 2.提供操作共享状态的方法
要通讯的子组件只需要通过props接收状态或操作状态的方法
props
- 组件要接受外部的数据应该通过props来实现
- props的作用:接受传递给组件的数据
- 传递数据:给组件标签添加属性
- 接收数据:函数组件通过参数props接收数据,类组件通过this.props接收数据
<Hello name="jack" age={19} /> function Hello(props){ return ( <div> 接收到的数据:{props.name} </div> ) }
props特点 可以给组件传递任意类型的数据
<Hello name="rose" age={19} colors={['red','green','blue']} fn={() => console.log('传的是函数')} tag={<p>这是一个p标签</p>} />
props是只读的对象 只能读取值 但是无法修改对象
使用类组件时,如果写了构造函数,应该将props传递给super() 否则无法在构造函数中获取到props
constructor(props) { super(props) }
props深入
children属性
1.表示组件标签的子节点,当组件标签有子节点时,props就会有该属性、
2.children属性与普通的props一样,值可以是任意值(文本,React元素,组件,函数)
function Hello {props}{
return {
<div>
组件的子节点:{props.children}
</div>
}
}
<Hello> 我是子节点 </Hello>
props校验
1.因为对于组件来说,props是外来的,无法保证组件使用者传入什么格式的数据
2.如果传入数据不对,会导致组件内部报错,且组件的使用者不知道明确的错误原因。
3.添加props校验,允许在创建组件的时候,就指定props的格式和类型。捕获使用组件时因为props导致的错误,增加组件的健壮性。
步骤
1.安装prop-types包
2.导入prop-type是包
3.使用组件名.propTypes={}给组件的props添加校验规则
4.校验规则通过PropTypes对象来指定
约束规则
1.常见类型:array bool func number object string
2.React元素类型 :element
3.必填项:isRequired
4.特定结构的对象: shape({})
//添加props校验
App.propTypes={
a:propTypes.number,
fn:propTypes.func.isRequired,
tag:PropTypes.element,
filter:PropTypes.shape({
area:PropTypes.string,
price:PropTypes,number
})
}
props默认值
场景:分页组件-》每页显示条数
作用:给props设置默认值,在未传入props时生效
App.defaultProps ={
pageSize:10
}
Context
跨多个组件传递数据 (eg 主题 语言)
Context提供了两个组件 Provider -》用来提供数据和Consumer-》用来消费数据
//1.调用React.creatContext() 创建Provider 和Consumer 两个组件
const { Provider,Consumer} = React.createContext()
//2.使用Provider组件作为父节点
<Provider>
<div className="App">
<Child1 />
</div>
</Provider>
//3.设置value属性,表示要传递的数据
<Provider value="pink">
//4.调用Consumer 组件接收数据
<Consumer>
{data => <span>data 参数表示接收到的数据 --{data}</span>
</Consumer>