# 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 (
this is a div
) } 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 ,