React入门(Day1)

111 阅读7分钟

写在前面,在公司写了一年的Angular,现在准备转React,收拾收拾开干

image.png

环境搭建

create-react-app是一个快速创建React开发环境的工具,底层由Webpack构建,封装了配置细节,开箱即用 执行命令:

npx create-react-app react-basic
cd react-basic
npm start

1.JSX基础

概念:JSX是JavaScript和XMl(HTML)的缩写,表示在JS代码中编写HTML模版结构,它是React中构建UI的方式

JSX高频场景:

1.1 JS表达式

在JSX中可以通过 大括号语法{} 识别JavaScript中的表达式,比如常见的变量、函数调用、方法调用等等; 注意:if语句,switch语句,变量声明属于语句,不是表达式,不能出现在{}中

  • 使用引号传递字符串
  • 使用JS变量
  • 函数调用和方法调用
  • 使用JavaScript对象
const number = 100;
function getName(){
  return 'Lily';
}
function App() {
  return (
    <div className="App">
      {'this is a str'}      {/*字符串识别*/}
      { number }             {/*js变量识别*/}
      { getName() }               {/*函数调用*/}
      { new Date().getDate() }    {/*方法调用*/}
      <div style={{color:'pink'}}> DIV </div>  {/*使用JS对象*/}
    </div>
  );
}
1.2 列表渲染

在JSX中可以使用原生js中的map方法 实现列表渲染,注意加上key。

const list = [
  { id: 1001, name: 'Vue'},
  { id: 1002, name: 'React'},
  { id: 1003, name: 'Angular'}
]

function App() {
  return (
     <ul>
       {list.map(item => <li key={item.id}>{item.id} {item.name}</li>)}
     </ul>
  );
}
1.3 条件渲染

image.png

语法:在React中,可以通过逻辑与运算符&& 三元表达式(?:) 实现基础的条件渲染

const isLogin = true;

{isLogin && <span>this a span</span>}
{isLogin ? <span>jack</span> : <span>loading...</span>}
1.4 复杂条件渲染
const type = 1  // 0|1|3

function getArticleJSX(){
  if(type === 0){
    return <div>无图模式模版</div>
  }else if(type === 1){
    return <div>单图模式模版</div>
  }else(type === 3){
    return <div>三图模式模版</div>
  }
}

function App(){
  return (
    <div>
        {/*调用函数渲染不同的模板*/}
      { getArticleJSX() }
    </div>
  )
}

2. React事件绑定

2.1 基础事件绑定
  • 语法 on + 事件名称 = { 事件处理程序/回调函数 },整体上遵循驼峰命名法;记住 事件后面不要加括号()
  • 使用事件参数:在事件回调函数中设置形参e即可
function App(){
  const clickHandler = (e)=>{
    console.log('button按钮点击了', e)
  }
  
  return (
    <button onClick={clickHandler}>click me</button>
  )
}
2.2 传递参数

image.png

image.png

3.组件基础使用

image.png

3.1 组件基础使用

在React中,一个组件就是首字母大写的函数,内部存放了组件的逻辑和视图UI, 渲染组件只需要把组件当成标签书写即可

// 1. 定义组件
function Button(){
  return <button>click me</button>
}

// 2. 使用组件
function App(){
  return (
    <div>
      {/* 自闭和 */}
      <Button/>
      {/* 成对标签 */}
      <Button></Button>
    </div>
  )
}

4. 组件状态管理-useState

4.1 基础使用

image.png

//useState实现计数器
import { useState } from "react";

function App() {
  //调用useState添加一个状态变量,count是状态变量,setCount是修改状态变量的方法
  const [count, setCount] = useState(0)
  //点击事件回调函数,用传入的新值修改count,重新使用新的count渲染UI
  const handleClick = () => {
    setCount(count+1)
  }
  return (
    <div>
      <button onClick={handleClick}>{count}</button>
    </div>
  );
}
4.2 状态的修改规则

在React中状态被认为是只读的,我们应该始终替换它而不是修改它, 直接修改状态不能引发视图更新

image.png

修改对象状态

对于对象类型的状态变量,应该始终给set方法一个全新的对象来进行修改

image.png

如果是数组,修改参数样例,先用中括号包起来,再用大括号包住替换的原始数组结构

const handlePublish = () => {
    setCommentList(
      [
        ...commentList,
        {
          rpid: 4,
          user: {
            uid: '30009257',
            avatar,
            uname: '黑马前端',
          },
          content: content,
          ctime: '10-19 09:00',
          like: 66,
        }
      ]
    )
  }

5.组件的基础样式处理

行内样式/class类名控制

image.png

补充:

image.png

*案例:B站评论

image.png

1. 渲染评论列表(核心思路)
  • 使用useState维护评论列表
  • 使用map方法对列表数据进行遍历渲染(别忘记key)
2. 删除评论

需求:

  • 只有自己的评论才显示删除按钮;
  • 点击删除按钮,删除当前评论,列表中不再显示

核心思路:

  • 删除显示-条件渲染
  • 删除功能-拿到当前项id,以id为条件对评论列表做filter过滤
3. 渲染tab + 点击高亮实现

需求: 点击哪个tab,哪个做高亮处理

核心思路: 点击谁就把谁的 type(独一无二的标识)记录 下来,然后和遍历时的 每一项的type做匹配 ,谁匹配到就设置高亮的类名。

4. 排序功能实现

需求: 点击最新,评论列表按照列表创建时间倒序排列(新的在前),点击最热按照点赞数排序(多的在前)

核心思路: 把评论列表状态数据进行不同的排序处理,当成新值传给set函数重新渲染视图UI

5. 发表评论功能

需求: 输入框评论内容,获取评论内容,点击发布按钮发布评论

实现方式: rpid要求一个唯一的随机数id - uuid ctime要求以当前时间为标准,生成固定格式 - dayjs

6. 清空内容并重新聚焦

清空内容 - 把控制input框的value状态设置为空串 重新聚焦 - 拿到input的dom元素,调用focus方法

6. 表单数据双向绑定

6.1 受控绑定(推荐)

核心绑定流程 1.通过value属性绑定react状态 2.绑定onChange事件,通过事件参数e拿到输入框最新的值,反向修改到react状态

image.png

6.2 非受控绑定

image.png

7. 组件通信

image.png

7.1 父子组件通信
7.1.1 父传子

image.png

function Son(props){
  return <div>{ props.name }</div>
}


function App(){
  const name = 'this is app name'
  return (
    <div>
       <Son name={name}/>
    </div>
  )
}
  • props是一个对象,里面包含了父组件传递过来的所有数据
  • 传递的是单向数据流,子组件无法修改父组件传递过来的数据

image.png

image.png

7.1.2 子传父

image.png

function Son({ onGetMsg }){
  const sonMsg = 'this is son msg'
  return (
    <div>
      {/* 在子组件中执行父组件传递过来的函数 */}
      <button onClick={()=>onGetMsg(sonMsg)}>send</button>
    </div>
  )
}


function App(){
const [msg, setMsg] = useState('')
  const getMsg = (msg) => {
       setMsg(msg)
  }
  
  return (
    <div>
       <div> {msg}</div>
      {/* 传递父组件中的函数到子组件 */}
       <Son onGetMsg={ getMsg }/>
    </div>
  )
}
7.2 兄弟组件通信

image.png

7.3 跨层组件通信

image.png

// App -> A -> B
import { createContext, useContext } from "react"

// 1. createContext方法创建一个上下文对象

const MsgContext = createContext() //变量首字母大写,遵循驼峰

function A () {
  return (
    <div>
      this is A component
      <B />
    </div>
  )
}

function B () {
  // 3. 在底层组件 通过useContext钩子函数使用数据
  const msg = useContext(MsgContext)
  return (
    <div>
      this is B compnent,{msg}
    </div>
  )
}

function App () {
  const msg = 'this is app msg'
  return (
    <div>
      {/* 2. 在顶层组件 通过Provider组件提供数据 */}
      <MsgContext.Provider value={msg}>
        this is App
        <A />
      </MsgContext.Provider>
    </div>
  )
}

export default App

8. useEffect

useEffect是一个React Hook函数,用于在React组件中创建不是由事件引起而是由渲染本身引起的操作(副作用), 比 如发送AJAX请求,更改DOM等等

image.png

说明:上面的组件中没有发生任何的用户事件,组件渲染完毕之后就需要和服务器要数据,整个过程属于“只由渲染引起的操作”

image.png

React的useEffect Hook和Vue的生命周期钩子函数有一些关联 useEffect 可以看作是以下几个生命周期函数的结合: componentDidMount\componentDidUpdtate\componentWillUnmount,这意味着useEffect可以在组件挂载mount\更新update\卸载unmount 时执行一些副作用。

image.png

9. 自定义Hook

概念:自定义Hook是以 use打头的函数,通过自定义Hook函数可以用来实现逻辑的封装和复用

image.png

// 封装自定义Hook
// 问题: 布尔切换的逻辑 当前组件耦合在一起的 不方便复用

import { useState } from "react"

function useToggle () {
  // 可复用的逻辑代码
  const [value, setValue] = useState(true)
  const toggle = () => setValue(!value)
  // 哪些状态和回调函数需要在其他组件中使用 return
  return {
    value,
    toggle
  }
}

// 封装自定义hook通用思路
// 1. 声明一个以use打头的函数
// 2. 在函数体内封装可复用的逻辑(只要是可复用的逻辑)
// 3. 把组件中用到的状态或者回调return出去(以对象或者数组)
// 4. 在哪个组件中要用到这个逻辑,就执行这个函数,解构出来状态和回调进行使用


function App () {
  const { value, toggle } = useToggle()
  return (
    <div>
      {value && <div>this is div</div>}
      <button onClick={toggle}>toggle</button>
    </div>
  )
}

image.png

10. 优化B站评论案例

image.png

优化需求 - 通过接口获取评论列表

  1. 使用json-server工具模拟接口服务,通过axios发送请求 json-server是一个快速以.json文件作为数据源模拟接口服务的工具 axios是一个广泛使用的前端请求库
  2. 使用useEffect调用接口获取数据
useEffect(() => {
    //发送网络请求
},[])

优化需求-自定义Hook函数封装数据请求 一般思路: 编写一个use打头的函数 函数内部编写封装的逻辑 return出去组件中用到的状态和方法 组件中调用函数解构赋值使用

function useXXX (){
    //状态逻辑
    return {
        //状态
        //方法
    }
}

优化需求-封装评论项item组件

image.png