目录
TODO1
React概述
React的使用
React脚手架的使用
全局安装
npx安装
在脚手架中使用React
JSX
1. JSX的基本使用
1.1 为什么用JSX
1.2 JSX简介
1.3 使用步骤
1.4 脚手架中能用JSX
1.5 注意点
2. 在JSX中使用JavaScript表达式
2.1 嵌入js表达式
2.2 注意点
3.JSX的条件渲染
4.JSX的列表渲染
5.JSX的样式处理
5.1 行内样式 style
5.2 类名 className
TODO2
组件
1.组件介绍
2.组件的两种创建方式
2.1 使用函数创建组件
2.2 使用类创建组件
2.3 将组件抽离为单独的js文件
事件处理
1.事件绑定
2.事件对象
3.有状态组件和无状态组件
4.state和setState()
4.1 state的基本使用
4.2 setState修改状态
4.3 从JSX中抽离事件处理程序
this指向
1.箭头函数
2.Function.prototype.bind()
3.class的实例方法
4.总结
表单处理
1.受控组件
2.非受控组件
TODO3
组件通讯
1.组件通讯的定义
2.组件通讯的三种方式
props
props深入
Context
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安装脚手架的区别
全局安装
React脚手架的使用
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
1. 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> )
2. 在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 elseconst 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 (<div>类组件</div>)}
}
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 (<div> 啊啊啊啊</div>)}
}
//导出组件
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的要求//初始化statethis.state ={count :0}
}//简洁版 实验性的public class fields语法
state = {count :0}render(){return (<div>有组件状态</div>
)
}
}
①super()函数用于访问和调用一个对象上的父对象上的函数
②在构造函数中使用时,super关键字将单独出现,并且必须在使用this关键字之前使用。
super关键字也可以调用父对象上的函数。
③ES6 class语法拯救世界了吗 为什么要用它(?)
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()
箭头函数中的this指向
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
<inputtype="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>
React 官方中文文档