# studyReact01
**Repository Path**: huayyds/study-react01
## Basic Information
- **Project Name**: studyReact01
- **Description**: 学习react入门
- **Primary Language**: JavaScript
- **License**: GPL-3.0
- **Default Branch**: second
- **Homepage**: https://gitee.com/huayyds/study-react01
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-07-28
- **Last Updated**: 2022-08-16
## Categories & Tags
**Categories**: Uncategorized
**Tags**: React, Redux, redux-saga
## README
# React起源
React 起源于 Facebook 的内部项目.
轻量级的视图层**库**!
React不是一个完整的MVC框架,最多可以认为是MVC中的V(View),甚至React并不非常认可MVC开发模式;React 构建页面 UI 的库。
可以简单地理解为,React 将界面分成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,就成了我们的页面。
# React的特性
1、声明式设计
2、高效--通过对DOM模拟(虚拟DOM),最大减少与DOM交互
3、灵活 --跟已知的库和框架很好配合
4、JSX--JavaScript语法的扩展
5、组件化 -- 通过构建组件,使代码复用,很好的应用在大项目开发中
6、单项响应的数据流 -- 减少重复代码
# 全局安装
## 全局安装create-react-app
**`npm install -g create-react-app`**
创建一个项目
**`create-react-app 项目名称`**
如果不想全局安装,可以直接使用npx
**`npx create-react-app 项目名称`**
## 常见问题:
**npm安装失败时**
**1、切换为npm镜像为淘宝镜像:`npm install cnpm -g --registry=https://registry.npm.taobao.org`**
**2、使用yarn,如果本来使用yarn还要失败,还得把yarn的源切换到国内**
**3、如果还没有办法解决,请删除node_modules及package-lock.json然后重新执行 npm install命令**
**4、再不能解决就删除node_modules及package-lock.json的同时清除npm缓存 npm cache clean --force 之后再执行 npm install 命令**
## 命令
### `npm start或yarn start`
启动项目
### `npm run build`
打包项目
# JSX 语法与组件
## 一、JSX 语法
### 1、JSX介绍
JSX 将 HTML 语法直接加入到 JavaScript 代码中,再通过翻译器转换到纯 JavaScript 后由浏览器执行。
会让代码更加直观并易于维护;编译过程由Babel 的 JSX 编译器实现。
**React.js 就把 JavaScript 的语法扩展了一下,让 JavaScript 语言能够支持这种直接在 JavaScript 代码里面编写类似 HTML 标签结构的语法,这样写起来就方便很多了。编译的过程会把类似 HTML 的 JSX结构转换成 JavaScript 的对象结构。**
所谓的 JSX 其实就是 JavaScript 对象,所以使用 React 和 JSX 的时候一定要经过编译的过程:
**`JSX —使用react构造组件,bable进行编译—> JavaScript对象 — ReactDOM.render() —>DOM元素 —>插入页面`**
#### **注意:**
1、在JSX中,HTML里面的class类名改为了**className**
2、在JSX中,HTML标签的for属性改为==> htmlFor( )
``
3、在JSX中,绑定事件采用on+首字母大写,原生的事件全是小写
onclick , React里的事件是驼峰 onClick ,**React** **的事件并不是原生事件,而是合成事件**
4、react推荐我们使用行内样式,因为react觉得每一个组件都是一个独立的整体
### 2、JSX中使用js表达式
**语法:**
`{ js表达式 }`
在组件内部要让一段逻辑执行,需要加上{}花括号,{}可以加变量,三元运算符等
**可以使用的表达式**
1. 字符串、数值、布尔值、null、undefined、object( [] / {} )
2. 1 + 2、'abc'.split('')、['a', 'b'].join('-')
3. fn()
**特别注意**
if 语句/ switch-case 语句/ 变量声明语句,这些叫做语句,不是表达式,不能出现在 `{}` 中!!
### 3、JSX列表渲染
实现:使用数组的`map` 方法
注意点:需要为遍历项添加 `key` 属性
1. key 在 HTML 结构中是看不到的,是 React 内部用来进行性能优化时使用
2. key 在当前列表中要唯一的字符串或者数值(String/Number)
3. 如果列表中有像 id 这种的唯一值,就用 id 来作为 key 值
4. 如果列表中没有像 id 这种的唯一值,就可以使用 index(下标)来作为 key 值
### 4、JSX条件渲染
实现:可以使用 `三元运算符` 或 `逻辑与(&&)运算符`
### 5、JSX样式处理
- 行内样式 - style
```javascript
this is a div
```
- 行内样式 - style - 更优写法
```javascript
const styleObj = {
color:red
}
function App() {
return (
)
}
export default App
```
- 类名 - className(推荐)
- 类名 - className - 动态类名控制
```javascript
this is a div
```
### 6、JSX注意事项
1. JSX必须有一个根元素,如果没有根节点,可以使用`<>>`(幽灵节点)替代
2. 所有标签必须形成闭合,成对闭合或者自闭合都可以
3. JSX中的语法更加贴近JS语法,属性名采用驼峰命名法 `class -> className` `for -> htmlFor`
4. JSX支持多行(换行),如果需要换行,需使用`()` 包裹,防止bug出现,例如**return加上小括号()可以换行表示一个整体可以多加标签**
## 二、React组件的基础
### 1、函数组件
**`目标任务:`** 能够独立使用函数完成react组件的创建和渲染
**概念**
使用 JS 的函数(或箭头函数)创建的组件,就叫做**函数组件**
```javascript
// 定义函数组件
function HelloFn () {
return 这是我的第一个函数组件!
}
// 定义类组件
function App () {
return (
{/* 渲染函数组件 */}
)
}
export default App
```
#### 注意:
1. 组件的名称**必须首字母大写**,react内部会根据这个来判断是组件还是普通的HTML标签
2. 函数组件**必须有返回值**,表示该组件的 UI 结构;如果不需要渲染任何内容,则返回 null
3. 组件就像 HTML 标签一样可以被渲染到页面中。组件表示的是一段结构内容,对于函数组件来说,渲染的内容是函数的**返回值**就是对应的内容
4. 使用函数名称作为组件标签名称,可以**成对**出现也可以**自闭合**
### 2、类组件
**`目标任务:`** 能够独立完成类组件的创建和渲染
使用 ES6 的 class 创建的组件,叫做**类(class)组件**
```JavaScript
// 引入React
import React from 'react'
// 定义类组件
class HelloC extends React.Component {
render () {
return 这是我的第一个类组件!
}
}
function App () {
return (
{/* 渲染类组件 */}
)
}
export default App
```
#### 注意:
1. **类名称也必须以大写字母开头**
2. 类组件应该继承 React.Component 父类,从而使用父类中提供的方法或属性
3. 类组件必须提供 render 方法**render 方法必须有返回值,表示该组件的 UI 结构**
### 类组件使用计算属性
计算属性:就是当依赖的数据(`state` / `props`)发生变化时,动态更新计算出来的值。
使用getter:
```jsx
class Comp extends react.Component {
state = {
count: 1,
};
// 两倍的count
// 当state发生变化的时候,doubleCount作为计算值也会是最新的
get doubleCount() {
return this.state.count * 2;
}
// 一个getter还可以依赖另外一个getter
// 读取getter的时候,直接读取即可,不用像函数一样执行
get doubleCountInChinese() {
return `两倍数字为${this.doubleCount}`;
}
increaseCount() {
this.setState({
count: this.state.count + 1,
});
}
render() {
return (
<>
count: {this.state.count}
doubleCount: {this.doubleCount}
doubleCountInChinese: {this.doubleCountInChinese}
>
);
}
}
```
这个getter其实跟vue中的`computed`计算属性和react hooks中的`useMemo`还是有略微的区别的:
- vue中的`computed`:会缓存结果,引用的数据发生变化时才重新计算;
- React hooks中的`useMemo`:会缓存结果,引用的数据发生变化时才重新计算;
- React类组件中的`getter`:不会缓存结果,每次重渲染时都会重新计算,性能略差一丢丢。
### 3、事件绑定
react 并不会真正的绑定事件到每一个具体《》的元素上,而是采用事件带来的模式,模拟事件机制
能够独立绑定任何事件并能获取到事件对象e
#### **3.1、如何绑定**
- 语法:
**事件处理on大写,驼峰写法**
on + 事件名称 = { 事件处理程序 } ,比如:`{}}>
`
- 注意点
**3.1.1、this.函数名 不要加()会立即执行,跟vue不同**
错误:``会立即执行
正确:**``**
**3.1.2、推荐:匿名箭头函数写法,可以传参数**
**` `**
**3.1.3、使用函数定义成箭头函数就不会导致this指向问题**
### 扩展知识
**js改变this指向:**
1. **call,改变this指向,自动执行函数**
2. **apply,改变this指向,自动执行函数**
3. **bind,改变this指向,不会自动执行函数,手动加()执行**
#### **3.2. 获取事件对象**
通过事件处理程序的参数获取事件对象e
```javascript
// 函数组件
function HelloFn () {
// 定义事件回调函数
const clickHandler = (e) => {
//阻止事件默认行为
e.preventDefault()
console.log('事件被触发了', e)
}
return (
// 绑定事件
百度
)
}
```
### 4、Ref的应用
#### 4.1、给标签设置ref属性ref="myname"
通过获取this.refs.myname,ref可以获取应用的真实DOM
#### 4.2、给组件设置ref=“myname”
**this.refs 被react删除了,有风险**
通过获取this.refs.myname,ref可以获取到组件对象
#### 4.3、新的写法 **(推荐)**
```javascript
myref=React.createRef()
//this.myref.current.value访问到值
```
## 三、组件的数据挂载方式
### 1、状态(state)
能够给组件添加状态和修改状态的值
#### (1)定义state
- ##### **第一种定义状态方法**
```javascript
state={
name:"海绵宝宝",
text:"收藏",
myshow:true
}
```
- **第二种定义状态方法**
```javascript
constructor() {
// super()继承
super()
this.state = {
name: "海绵宝宝",
text: "收藏",
myshow: true
}
}
```
通过this.state.name访问读取状态
#### (2)setState
**不能直接修改state数据 ,通过this.setState间接修改更新**
```javascript
```
```
this.setState({ 要修改的部分数据 })
```
- setState方法作用
1. 1. 修改state中的数据状态
2. 更新UI
- setState有两个参数
第一个参数可以是对象,也可以是方法return一个对象,这个参数叫做updater
**参数是对象:**
```Javascript
this.setState({ isLiked: !this.state.isLiked })
```
**参数是方法:**
```javascript
this.setState((prevState, props) => { return { isLiked: !prevState.isLiked } })
```
注意的是这个方法接收两个参数,第一个是上一次的state, 第二个是props
setState 是异步的,所以想要获取到最新的state,没有办法获取,就有了第二个参数,这是一个可选
的回调函数
```javascript
this.setState((prevState, props) => { return { isLiked: !prevState.isLiked } }, () => { console.log('回调里的',this.state.isLiked) })
console.log('setState外部的',this.state.isLiked)
```
**setSate处在同步逻辑中,异步更新状态,异步更新真实dom,为了性能**
**setSate处在异步逻辑中,同步更新状态,同步更新真实dom**
**setSate接受第二个参数,是回调函数,状态和dom更新完后会触发**
### 2、属性(props)
props 是正常是外部传入的,组件内部也可以通过一些方式来初始化的设置,属性不能被组件自己更
改,但是你可以通过父组件主动重新渲染的方式来传入新的 props
属性是描述性质、特点的,组件自己不能随意更改。
之前的组件代码里面有 props 的简单使用,总的来说,在使用一个组件的时候,可以把参数放在标签的
属性当中,所有的属性都会作为组件 props 对象的键值。通过箭头函数创建的组件,需要通过函数的
参数来接收 prop:
**(1) 在组件上通过key=value 写属性,通过this.props获取属性,这样组件的可复用性提高了。**
**(2) 注意在传参数时候,如果写成isShow="true" 那么这是一个字符串 如果写成isShow={true} 这个是布尔值**
**(3) {...对象} 展开赋值**
**简写:如果跟定义变量一致,可以使用扩展运算符**\
**``**
**(4) 默认属性值**
使用类静态属性声明默认值,`static defaultProps = {}`
```javascript
*.defaultProps = { }static defaultProps = { myname:"默认的myname", myshow:true }
```
**(5) prop-types 属性验证 **
1. 安装属性校验包:`yarn add prop-types 或 npm i prop-types`
2. 导入`prop-types` 包
3. 使用 `组件名.propTypes = {}` 给组件添加校验规则
```javascript
import propTypes from "prop-types";
//第一种
*.propTypes={ name:propTypes.string, age:propTypes.number }
//第二种
static propTypes={ myname:propTypes.string, myshow:propTypes.bool }
```
```javascript
// 使用静态属性
static propTypes={
title:propTypes.string,
leftShow:propTypes.bool
}
// 静态默认属性,给属性默认值
static defaultProps={
leftShow:true
}
render() {
let { title, leftShow } = this.props
return (
<>
{leftShow===true && }
Navbar组件--{title}
>
)
}
```
```javascript
// 以下写法麻烦,放在类里写较好,加上static
// 类属性
// Navbar.propTypes={
// title:propTypes.string,
// leftShow:propTypes.bool
// }
// 类默认属性
// Navbar.defaultProps={
// leftShow:true
// }
```
#### props校验-规则说明
**四种常见结构**
1. 常见类型:array、bool、func、number、object、string
2. React元素类型:element
3. 必填项:isRequired
4. 特定的结构对象:shape({})
```javascript
// 常见类型
optionalFunc: PropTypes.func,
// 必填 只需要在类型后面串联一个isRequired
requiredFunc: PropTypes.func.isRequired,
// 特定结构的对象
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
})
```
### **3**、**属性vs状态**
相似点:都是纯js对象,都会触发render更新,都具有确定性(状态/属性相同,结果相同)
不同点:
1. 属性能从父组件获取,状态不能
2. 属性可以由父组件修改,状态不能
3. 属性能在内部设置默认值,状态也可以,设置方式不一样
4. 属性不在组件内部修改,状态要在组件内部修改
5. 属性能设置子组件初始值,状态不可以
6. 属性可以修改子组件的值,状态不可以
state 的主要作用是用于组件保存、控制、修改自己的可变状态。state是一个局部的、只能被组件自身控制的数据源。
state 中状态可以通过 this.setState 方法进行更新, setState 会导致组件的重新渲
染。
props 的主要作用是让使用该组件的父组件可以传入参数来配置该组件。
没有 state 的组件叫**无状态组件**
设置了 state 的叫做**有状态组件**
## 四、表单中的受控组件和非受控组件
### 1、非受控组件
文本框的状态不受react组件的state中的状态控制,直接通过原生dom获取输入框的值
可以 **使用 ref** 来从 DOM 节点中获取表单数据,就是非受控组件
1. 导入`createRef` 函数
2. 调用createRef函数,创建一个ref对象,存储到名为`msgRef`的实例属性中
3. 为input添加ref属性,值为`msgRef`
4. 在按钮的事件处理程序中,通过`msgRef.current`即可拿到input对应的dom元素,而其中`msgRef.current.value`拿到的就是文本框的值
```javascript
export default class App extends Component {
myref=React.createRef()
render() {
return (
登录页
{/* value属性无法输入值,修改为defaultValue就可控制后续的更新 */}
{/* value值是在受控组件使用,而defaultValue是在非受控组件使用 */}
)
}
}
```
在非受控组件中,经常希望 React 能赋予组件一个初始值,但是不去控制后续的更新。 在这种情况下, 你可以指定一个defaultValue 属性,而不是 value 。
同样, **** 和 **** 支持 defaultChecked ,