目录
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
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 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'
组件
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(
- )
- }
- }
- //渲染组件
- ReactDOM.render(<App/>,document.getElementById('root'))
3.有状态组件和无状态组件
状态 state即数据
- 函数组件叫做无状态组件 只负责数据展示(静态)
- 类组件叫做有状态组件 负责更新UI (动态)
4.state和setState()
4.1 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 (
-
- )
- }
- }
2.Function.prototype.bind()
- class Cc extends React.Component{
- constructor() {
- super()
- this.onIncrement = this.onIncrement.bind(this)
- }
- //省略onIncrement
- render(){
- return (
-
- )
- }
- }
3.class的实例方法
①利用箭头函数形式的class实例方法
②该语法是实验性语法 但是由于babel的存在可以直接用(编译JSX的语法包)
- class Cc extends React.Component{
- onIncrement =() =>{
- this.setState({...})
- }
- render(){
- return (
-
- )
- }
- }
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的思想
组件通讯
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>