react简介(搬运)

# React简介

**react是什么?**

React用于构建用户界面的JS库。是一个将数据渲染为HTML视图的开源JS库。**

1.原生JS操作DOM繁琐,效率低

2.使用JS直接操作DOM,浏览器会进行大量的重绘重排

3.原生JS没有组件化编码方案,代码复用低

## **React有什么特点**

1- 声明式UI(JSX)

写UI就和写普通的HTML一样,抛弃命令式的繁琐实现


 

![img](https://cdn.nlark.com/yuque/0/2022/png/274425/1654489480461-0cfa5cac-eb47-4629-8f11-a7ca1d8c0227.png)



 

## 2- 组件化

组件是react中最重要的内容,组件可以通过搭积木的方式拼成一个完整的页面,通过组件的抽象可以增加复用能力和提高可维护性

![img](https://cdn.nlark.com/yuque/0/2022/png/274425/1659285398963-681a495b-1347-4a9f-bc62-1be28ed805eb.png)

# 环境初始化

## 1. 使用脚手架创建项目

-  打开命令行窗口

-  执行命令

```bash

$ npx create-react-app react-basic

```


 

说明:

1. 1. npx create-react-app 是固定命令,`create-react-app`是React脚手架的名称

   2. react-basic表示项目名称,可以自定义,保持语义化

   3. npx 命令会帮助我们临时安装create-react-app包,然后初始化项目完成之后会自自动删掉,所以不需要全局安装create-react-app

-  启动项目

```bash

$ yarn start

or

$ npm start

```

## 2. 项目目录说明调整

-  目录说明

1. 1. `src` 目录是我们写代码进行项目开发的目录

   2. `package.json`  中俩个核心库:react 、react-dom

-  目录调整

1. 1. 删除src目录下自带的所有文件,只保留app.js根组件和index.js

   2. 创建index.js文件作为项目的入口文件,在这个文件中书写react代码即可

-  入口文件说明

```jsx

import React from 'react'

import ReactDOM from 'react-dom'

import './index.css'

// 引入根组件App

import App from './App'

// 通过调用ReactDOM的render方法渲染App根组件到id为root的dom节点上

ReactDOM.render(

  <React.StrictMode>

    <App />

  </React.StrictMode>,

  document.getElementById('root')

)

```

 JSX基础

## 1. JSX介绍

概念:JSX是 JavaScript XML(HTML)的缩写,表示在 JS 代码中书写 HTML 结构

作用:在React中创建HTML结构(页面UI结构)

优势:

1. 采用类似于HTML的语法,降低学习成本,会HTML就会JSX

2. 充分利用JS自身的可编程能力创建HTML结构

注意:JSX 并不是标准的 JS 语法,是 JS 的语法扩展,浏览器默认是不识别的,脚手架中内置的 [@babel/plugin-transform-react-jsx](@babel/plugin-transform-react-jsx) 包,用来解析该语法



 

![img](https://cdn.nlark.com/yuque/0/2022/png/274425/1654489661908-d354840e-78b8-43ad-a882-8129742c794e.png)



 

## 2. JSX中使用js表达式

**语法**

```

{ JS 表达式 }

const name = '柴柴'

<h1>你好,我叫{name}</h1>   //    <h1>你好,我叫柴柴</h1>

```

**可以使用的表达式**

1. 字符串、数值、布尔值、null、undefined、object( [] / {} )

2. 1 + 2、'abc'.split('')、['a', 'b'].join('-')

3. fn()

**特别注意**

if 语句/ switch-case 语句/ 变量声明语句,这些叫做语句,不是表达式,不能出现在 `{}` 中!!

## 3. JSX列表渲染

页面的构建离不开重复的列表结构,比如歌曲列表,商品列表等,我们知道vue中用的是v-for,react这边如何实现呢?

实现:使用数组的`map` 方法

```jsx

// 来个列表

const songs = [

  { id: 1, name: '痴心绝对' },

  { id: 2, name: '像我这样的人' },

  { id: 3, name: '南山南' }

]

function App() {

  return (

    <div className="App">

      <ul>

        {

          songs.map(item => <li>{item.name}</li>)

        }

      </ul>

    </div>

  )

}

export default App

```

注意点:需要为遍历项添加 `key` 属性

![img](https://cdn.nlark.com/yuque/0/2022/png/274425/1654489746660-d500357d-1e62-4016-a25f-d36594fdfead.png)

1. key 在 HTML 结构中是看不到的,是 React 内部用来进行性能优化时使用

2. key 在当前列表中要唯一的字符串或者数值(String/Number)

3. 如果列表中有像 id 这种的唯一值,就用 id 来作为 key 值

4. 如果列表中没有像 id 这种的唯一值,就可以使用 index(下标)来作为 key 值

## 4. JSX条件渲染

作用:根据是否满足条件生成HTML结构,比如Loading效果

实现:可以使用 `三元运算符` 或  `逻辑与(&&)运算符`

```jsx

// 来个布尔值

const flag = true

function App() {

  return (

    <div className="App">

      {/* 条件渲染字符串 */}

      {flag ? 'react真有趣' : 'vue真有趣'}

      {/* 条件渲染标签/组件 */}

      {flag ? <span>this is span</span> : null}

    </div>

  )

}

export default App

```

## 5. JSX样式处理

-  行内样式 - style

```jsx

function App() {

  return (

    <div className="App">

      <div style={{ color: 'red' }}>this is a div</div>

    </div>

  )

}

export default App

```

-  行内样式 - style - 更优写法

```jsx

const styleObj = {

    color:red

}

function App() {

  return (

    <div className="App">

      <div style={ styleObj }>this is a div</div>

    </div>

  )

}

export default App

```

-  类名 - className(推荐)

```css

.title {

  font-size: 30px;

  color: blue;

}

```

## 6. JSX注意事项

1. JSX必须有一个根节点,如果没有根节点,可以使用`<></>`(幽灵节点)替代

2. 所有标签必须形成闭合,成对闭合或者自闭合都可以

3. JSX中的语法更加贴近JS语法,属性名采用驼峰命名法  `class -> className`  `for -> htmlFor`

4. JSX支持多行(换行),如果需要换行,需使用`()` 包裹,防止bug出现

## 函数组件

**概念**

使用 JS 的函数(或箭头函数)创建的组件,就叫做`函数组件`

**组件定义与渲染**

```jsx

// 定义函数组件

function HelloFn () {

  return <div>这是我的第一个函数组件!</div>

}

// 定义类组件

function App () {

  return (

    <div className="App">

      {/* 渲染函数组件 */}

      <HelloFn />

      <HelloFn></HelloFn>

    </div>

  )

}

export default App**

```

1. 组件的名称**必须首字母大写**,react内部会根据这个来判断是组件还是普通的HTML标签

2. 函数组件**必须有返回值**,表示该组件的 UI 结构;如果不需要渲染任何内容,则返回 null

3. 组件就像 HTML 标签一样可以被渲染到页面中。组件表示的是一段结构内容,对于函数组件来说,渲染的内容是函数的**返回值**就是对应的内容

4. 使用函数名称作为组件标签名称,可以成对出现也可以自闭合

5. ## 函数组件的事件绑定

   `目标任务:`  能够独立绑定任何事件并能获取到事件对象e

   ### 1. 如何绑定事件

   -  语法

     on + 事件名称 = { 事件处理程序 } ,比如:`<div onClick={ onClick }></div>`

   -  注意点

     react事件采用驼峰命名法,比如:onMouseEnter、onFocus

   -  样例

   ```jsx

   // 函数组件

   function HelloFn () {

     // 定义事件回调函数

     const clickHandler = () => {

       console.log('事件被触发了')

     }

     return (

       // 绑定事件

       <button onClick={clickHandler}>click me!</button>

     )

   }

   ```

   ### 2. 获取事件对象

    获取事件对象e只需要在 事件的回调函数中 补充一个形参e即可拿到

   ```jsx

   // 函数组件

   function HelloFn () {

     // 定义事件回调函数

     const clickHandler = (e) => {

       console.log('事件被触发了', e)

     }

     return (

       // 绑定事件

       <button onClick={clickHandler}>click me!</button>

     )

   }

   ```

   ### 3. 传递额外参数

   解决思路: 改造事件绑定为箭头函数 在箭头函数中完成参数的传递

   ```jsx

   import React from "react"

   

   // 如何获取额外的参数?

   // onClick={ onDel } -> onClick={ () => onDel(id) }

   // 注意: 一定不要在模板中写出函数调用的代码 onClick = { onDel(id) }  bad!!!!!!

   

   const TestComponent = () => {

     const list = [

       {

         id: 1001,

         name: 'react'

       },

       {

         id: 1002,

         name: 'vue'

       }

     ]

     const onDel = (e, id) => {

       console.log(e, id)

     }

     return (

         <ul>

           {list.map(item =>(

              <li key={item.id}>

                   {item.name}

                   <button onClick={(e) => onDel(e, item.id)}>x</button>

              </li>

           ))}

         </ul>

     )

   }

   

   function App () {

     return (

       <div>

         <TestComponent />

       </div>

     )

   }

   

   

   export default App

   ```

   # React组件通信

   ## 组件通信的意义

   组件是独立且封闭的单元,默认情况下组件**只能使用自己的数据(state)**

   组件化开发的过程中,完整的功能会拆分多个组件,在这个过程中不可避免的需要互相传递一些数据

   为了能让各组件之间可以进行互相沟通,数据传递,这个过程就是组件通信

   ## 父传子实现

   **实现步骤**

   1.  父组件提供要传递的数据  -  `state`

   2.  给子组件标签`添加属性`值为 state中的数据

   3.  子组件中通过 `props` 接收父组件中传过来的数据

   1. 1. 类组件使用this.props获取props对象

      2. 函数式组件直接通过参数获取props对象

   

   ![img](https://cdn.nlark.com/yuque/0/2022/png/274425/1654490432739-ea283505-3ddd-4403-9fba-7735b04b451e.png)

   **代码实现**

   ```jsx

   import React from 'react'

   

   // 函数式子组件

   function FSon(props) {

     console.log(props)

     return (

       <div>

         子组件1

         {props.msg}

       </div>

     )

   }

   

   // 类子组件

   class CSon extends React.Component {

     render() {

       return (

         <div>

           子组件2

           {this.props.msg}

         </div>

       )

     }

   }

   // 父组件

   class App extends React.Component {

     state = {

       message: 'this is message'

     }

     render() {

       return (

         <div>

           <div>父组件</div>

           <FSon msg={this.state.message} />

           <CSon msg={this.state.message} />

         </div>

       )

     }

   }

   

   export default App

   ```

   ## props说明

   **1.  props是只读对象(readonly)**

   根据单项数据流的要求,子组件只能读取props中的数据,不能进行修改

   **2. props可以传递任意数据**

   数字、字符串、布尔值、数组、对象、`函数、JSX`

   ```jsx

   class App extends React.Component {

     state = {

       message: 'this is message'

     }

     render() {

       return (

         <div>

           <div>父组件</div>

           <FSon

             msg={this.state.message}

             age={20}

             isMan={true}

             cb={() => { console.log(1) }}

             child={<span>this is child</span>}

           />

           <CSon msg={this.state.message} />

         </div>

       )

     }

   }

   ```

   ![img](https://cdn.nlark.com/yuque/0/2022/png/274425/1654490465147-2322a19d-104f-438d-a017-2725073ec0d7.png)

   

   ## 子传父

   **实现步骤**

   1. 父组件提供一个回调函数 - 用于接收数据

   2. 将函数作为属性的值,传给子组件

   3. 子组件通过props调用 回调函数

   4. 将子组件中的数据作为参数传递给回调函数

   

   ![img](https://cdn.nlark.com/yuque/0/2022/png/274425/1654490502446-0596a169-847f-4446-91ce-a9a0237a9074.png)

   **代码实现**

   ```jsx

   import React from 'react'

   

   // 子组件

   function Son(props) {

     function handleClick() {

       // 调用父组件传递过来的回调函数 并注入参数

       props.changeMsg('this is newMessage')

     }

     return (

       <div>

         {props.msg}

         <button onClick={handleClick}>change</button>

       </div>

     )

   }

   class App extends React.Component {

     state = {

       message: 'this is message'

     }

     // 提供回调函数

     changeMessage = (newMsg) => {

       console.log('子组件传过来的数据:',newMsg)

       this.setState({

         message: newMsg

       })

     }

     render() {

       return (

         <div>

           <div>父组件</div>

           <Son

             msg={this.state.message}

             // 传递给子组件

             changeMsg={this.changeMessage}

           />

         </div>

       )

     }

   }

   

   export default App

   ```

   # Hooks基础

   Hooks的本质:**一套能够使函数组件更强大,更灵活的“钩子”**

   ## useState

   ### 1. 基础使用

   **作用**

   useState为函数组件提供状态(state)

   **使用步骤**

   1. 导入 `useState` 函数

   2. 调用 `useState` 函数,并传入状态的初始值

   3. 从`useState`函数的返回值中,拿到状态和修改状态的方法

   4. 在JSX中展示状态

   5. 调用修改状态的方法更新状态

   **代码实现**

   ```jsx

   import { useState } from 'react'

   

   function App() {

     // 参数:状态初始值比如,传入 0 表示该状态的初始值为 0

     // 返回值:数组,包含两个值:1 状态值(state) 2 修改该状态的函数(setState)

     const [count, setCount] = useState(0)

     return (

       <button onClick={() => { setCount(count + 1) }}>{count}</button>

     )

   }

   export default App

   ```

   ### 2. 状态的读取和修改

   **读取状态**

   该方式提供的状态,是函数内部的局部变量,可以在函数内的任意位置使用

   **修改状态**

   1. setCount是一个函数,参数表示`最新的状态值`

   2. 调用该函数后,将使用新值替换旧值

   3. 修改状态后,由于状态发生变化,会引起视图变化

   **注意事项**

   1. 修改状态的时候,一定要使用新的状态替换旧的状态,不能直接修改旧的状态,尤其是引用类型

   ### 3. 组件的更新过程

   `本节任务:`  能够理解使用hook之后组件的更新情况

   函数组件使用 **useState** hook 后的执行过程,以及状态值的变化

   - 组件第一次渲染

   1. 1. 从头开始执行该组件中的代码逻辑

      2. 调用 `useState(0)` 将传入的参数作为状态初始值,即:0

      3. 渲染组件,此时,获取到的状态 count 值为: 0

   - 组件第二次渲染

   1. 1. 点击按钮,调用 `setCount(count + 1)` 修改状态,因为状态发生改变,所以,该组件会重新渲染

      2. 组件重新渲染时,会再次执行该组件中的代码逻辑

      3. 再次调用 `useState(0)`,此时 **React 内部会拿到最新的状态值而非初始值**,比如,该案例中最新的状态值为 1

      4. 再次渲染组件,此时,获取到的状态 count 值为:1

   注意:**useState 的初始值(参数)只会在组件第一次渲染时生效**。也就是说,以后的每次渲染,useState 获取到都是最新的状态值,React 组件会记住每次最新的状态值

   ```jsx

   import { useState } from 'react'

   

   function App() {

     const [count, setCount] = useState(0)

     // 在这里可以进行打印测试

     console.log(count)

     return (

       <button onClick={() => { setCount(count + 1) }}>{count}</button>

     )

   }

   export default App

   ```

   ### 4. 使用规则

   1.  `useState` 函数可以执行多次,每次执行互相独立,每调用一次为函数组件提供一个状态

   ```javascript

   function List(){

     // 以字符串为初始值

     const [name, setName] = useState('cp')

     // 以数组为初始值

     const [list,setList] = useState([])

   }

   ```

   1.  `useState` 注意事项

   1. 1.  只能出现在函数组件或者其他hook函数中

      2.  不能嵌套在if/for/其它函数中(react按照hooks的调用顺序识别每一个hook)

   ```javascript

   let num = 1

   function List(){

     num++

     if(num / 2 === 0){

        const [name, setName] = useState('cp')

     }

     const [list,setList] = useState([])

   }

   // 俩个hook的顺序不是固定的,这是不可以的!!!

   ```

   1.

   ## useEffect

   **使用步骤**

   1. 导入 `useEffect` 函数

   2. 调用 `useEffect` 函数,并传入回调函数

   3. 在回调函数中编写副作用处理(dom操作)

   4. 修改数据状态

   5. 检测副作用是否生效

   **代码实现**

   ```jsx

   import { useEffect, useState } from 'react'

   

   function App() {

     const [count, setCount] = useState(0)

   

     useEffect(()=>{

       // dom操作

       document.title = `当前已点击了${count}次`

     })

     return (

       <button onClick={() => { setCount(count + 1) }}>{count}</button>

     )

   }

   

   export default App

   ```

   ### 3. 依赖项控制执行时机

   **1. 不添加依赖项**

   组件首次渲染执行一次,以及不管是哪个状态更改引起组件更新时都会重新执行

   1. 组件初始渲染

   2. 组件更新 (不管是哪个状态引起的更新)

   

   ```jsx

   useEffect(()=>{

       console.log('副作用执行了')

   })

   ```

   **2. 添加空数组**

   组件只在首次渲染时执行一次

   ```jsx

   useEffect(()=>{

     console.log('副作用执行了')

   },[])

   ```

   

   **3. 添加特定依赖项**

   副作用函数在首次渲染时执行,在依赖项发生变化时重新执行

   ```jsx

   function App() {  

       const [count, setCount] = useState(0)  

       const [name, setName] = useState('zs')

       

       useEffect(() => {    

           console.log('副作用执行了')  

       }, [count])  

       

       return (    

           <>      

            <button onClick={() => { setCount(count + 1) }}>{count}</button>      

            <button onClick={() => { setName('cp') }}>{name}</button>    

           </>  

       )

   }

   ```

   **注意事项**

   useEffect 回调函数中用到的数据(比如,count)就是依赖数据,就应该出现在依赖项数组中,如果不添加依赖项就会有bug出现

   ## useContext

   **实现步骤**

   1. 使用`createContext` 创建Context对象

   2. 在顶层组件通过`Provider` 提供数据

   3. 在底层组件通过`useContext`函数获取数据

   **代码实现**

   ```jsx

   import { createContext, useContext } from 'react'

   // 创建Context对象

   const Context = createContext()

   

   function Foo() {  

       return <div>Foo <Bar/></div>

   }

   

   function Bar() {  

       // 底层组件通过useContext函数获取数据  

       const name = useContext(Context)  

       return <div>Bar {name}</div>

   }

   

   function App() {  

       return (    

           // 顶层组件通过Provider 提供数据    

           <Context.Provider value={'this is name'}>    

               <div><Foo/></div>    

           </Context.Provider>  

       )

   }

   

   export default App

   ```

   

   ##

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值