稍微学学react

news2024/11/22 17:24:43

文章开始前,先划划水~

今日份开心:

今天看之前发布的按钮npm包下载量有162次,早知道好好做了

今日份不开心:

爬岗位看到一个整体都挺满意的岗位,公司位置和发展大方向都好喜欢!!!不过他的技术栈是react和nextjs的优先,这两个好像都没学过。QAQ~~~~这就是传说中的书到用时方恨少么?还有hybird跨段经验的优先,这块也没有学过,啊!我怎么那么菜!!(狗叫+emo中!!!)

现在学估计也来不及了,但是为了防止以后错失良机,还是学学吧(最近其实超级想去学游戏引擎!)

先学学react吧,直接用黑马的教案好了,前端我好像主要都是看的黑马的教程,黑马的主要特点就是讲的比较细,教案比较完整,比较适合没基础的新人,有基础的老人看的话可能会觉得又臭又长哈哈。

正片开始~!!

好几个月没学大的新技术栈了。学习启动!!!!!(当写到这个时候我还是个react小白)

其实以上的优势我觉得vue也具备···

项目开始

npx create-react-app react-basic

用惯了Vue看这个确实有点不习惯

知识点1.什么是JSX

JS和XML(HTML)的缩写,是react中创建UI的方式,指的是在JS中编写HTML

应该就是用JS创建实例吧,并不是标准的JS写法,其实还是每太理解作用

但看到下一个例子的时候就有点恍然大明白了,真的是吧JS和html融合了哈哈

基础实例渲染+条件渲染(相当于vue中的v-for和v-if吧)

知识点2.react事件绑定

讲了基本用法和如何传递事件对象和参数

function App(){
  const clickHandler = ()=>{
    console.log('button按钮点击了')
  }
  return (
    <button onClick={clickHandler}>click me</button>
  )
}

function App(){
  const clickHandler = (e)=>{
    console.log('button按钮点击了', e)
  }
  return (
    <button onClick={clickHandler}>click me</button>
  )
}

function App(){
  const clickHandler = (name)=>{
    console.log('button按钮点击了', name)
  }
  return (
    <button onClick={()=>clickHandler('jack')}>click me</button>
  )
}

function App(){
  const clickHandler = (name,e)=>{
    console.log('button按钮点击了', name,e)
  }
  return (
    <button onClick={(e)=>clickHandler('jack',e)}>click me</button>
  )
}

知识点3.组件使用+小案例

useState,这段代码我看着有点蒙。哈哈,先往下继续看

从状态修改规则来看,要替换才能重新渲染,只用count++这种修改而非替换,无法重新渲染

现在明白了,定义时第二个为替换函数,专门用来替换状态变量,即set个全新的对象

下面有个实例,npm  run start 启动下项目

不得不说启动的速度相比vue慢了不少、、

只看文档不看视频学还真有点费劲。火速去看了眼,发现是忘记了npm install下载依赖了·····

厘一下代码······主要是在app.js完成结构,在app.scss完成样式,json就是模拟数据库使用

import { useState } from 'react'
import './App.scss'
import avatar from './images/bozai.png'
import orderBy from 'lodash/orderBy'

/**
 * 评论列表的渲染和操作
 *
 * 1. 根据状态渲染评论列表
 * 2. 删除评论
 */

// 评论列表数据
const defaultList = [
  {
    // 评论id
    rpid: 3,
    // 用户信息
    user: {
      uid: '13258165',
      avatar: '',
      uname: '周杰伦',
    },
    // 评论内容
    content: '哎哟,不错哦',
    // 评论时间
    ctime: '10-18 08:15',
    like: 88,
  },
  {
    rpid: 2,
    user: {
      uid: '36080105',
      avatar: '',
      uname: '许嵩',
    },
    content: '我寻你千百度 日出到迟暮',
    ctime: '11-13 11:29',
    like: 88,
  },
  {
    rpid: 1,
    user: {
      uid: '30009257',
      avatar,
      uname: '黑马前端',
    },
    content: '学前端就来黑马',
    ctime: '10-19 09:00',
    like: 66,
  },
]
// 当前登录用户信息
const user = {
  // 用户id
  uid: '30009257',
  // 用户头像
  avatar,
  // 用户昵称
  uname: '黑马前端',
}

/**
 * 导航 Tab 的渲染和操作
 *
 * 1. 渲染导航 Tab 和高亮
 * 2. 评论列表排序
 *  最热 => 喜欢数量降序
 *  最新 => 创建时间降序
 */

// 导航 Tab 数组
const tabs = [
  { type: 'hot', text: '最热' },
  { type: 'time', text: '最新' },
]

const App = () => {
  // 导航 Tab 高亮的状态
  const [activeTab, setActiveTab] = useState('hot')
  const [list, setList] = useState(defaultList)

  // 删除评论
  const onDelete = rpid => {
    // 如果要删除数组中的元素,需要调用 filter 方法,并且一定要调用 setList 才能更新状态
    setList(list.filter(item => item.rpid !== rpid))
  }

  // tab 高亮切换
  const onToggle = type => {
    setActiveTab(type)
    let newList
    if (type === 'time') {
      // 按照时间降序排序
      // orderBy(对谁进行排序, 按照谁来排, 顺序)
      newList = orderBy(list, 'ctime', 'desc')
    } else {
      // 按照喜欢数量降序排序
      newList = orderBy(list, 'like', 'desc')
    }
    setList(newList)
  }

  return (
    <div className="app">
      {/* 导航 Tab */}
      <div className="reply-navigation">
        <ul className="nav-bar">
          <li className="nav-title">
            <span className="nav-title-text">评论</span>
            {/* 评论数量 */}
            <span className="total-reply">{list.length}</span>
          </li>
          <li className="nav-sort">
            {/* 高亮类名: active */}
            {tabs.map(item => {
              return (
                <div
                  key={item.type}
                  className={
                    item.type === activeTab ? 'nav-item active' : 'nav-item'
                  }
                  onClick={() => onToggle(item.type)}
                >
                  {item.text}
                </div>
              )
            })}
          </li>
        </ul>
      </div>

      <div className="reply-wrap">
        {/* 发表评论 */}
        <div className="box-normal">
          {/* 当前用户头像 */}
          <div className="reply-box-avatar">
            <div className="bili-avatar">
              <img className="bili-avatar-img" src={avatar} alt="用户头像" />
            </div>
          </div>
          <div className="reply-box-wrap">
            {/* 评论框 */}
            <textarea
              className="reply-box-textarea"
              placeholder="发一条友善的评论"
            />
            {/* 发布按钮 */}
            <div className="reply-box-send">
              <div className="send-text">发布</div>
            </div>
          </div>
        </div>
        {/* 评论列表 */}
        <div className="reply-list">
          {/* 评论项 */}
          {list.map(item => {
            return (
              <div key={item.rpid} className="reply-item">
                {/* 头像 */}
                <div className="root-reply-avatar">
                  <div className="bili-avatar">
                    <img
                      className="bili-avatar-img"
                      src={item.user.avatar}
                      alt=""
                    />
                  </div>
                </div>

                <div className="content-wrap">
                  {/* 用户名 */}
                  <div className="user-info">
                    <div className="user-name">{item.user.uname}</div>
                  </div>
                  {/* 评论内容 */}
                  <div className="root-reply">
                    <span className="reply-content">{item.content}</span>
                    <div className="reply-info">
                      {/* 评论时间 */}
                      <span className="reply-time">{item.ctime}</span>
                      {/* 评论数量 */}
                      <span className="reply-time">点赞数:{item.like}</span>
                      {user.uid === item.user.uid && (
                        <span
                          className="delete-btn"
                          onClick={() => onDelete(item.rpid)}
                        >
                          删除
                        </span>
                      )}
                    </div>
                  </div>
                </div>
              </div>
            )
          })}
        </div>
      </div>
    </div>
  )
}

export default App

知识点4.数据绑定

可以通过绑定Dom或者绑定值来实现实时渲染

知识点5.组件通信

父传子

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


function App(){
  const name = 'this is app name'
  return (
    <div>
       <Son name={name}/>
    </div>
  )
}

子传父

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


function App(){
  const getMsg = (msg)=>console.log(msg)
  
  return (
    <div>
      {/* 传递父组件中的函数到子组件 */}
       <Son onGetMsg={ getMsg }/>
    </div>
  )
}

兄弟组件:通过共同的父组件进行传递

// 1. 通过子传父 A -> App
// 2. 通过父传子 App -> B

import { useState } from "react"

function A ({ onGetAName }) {
  // Son组件中的数据
  const name = 'this is A name'
  return (
    <div>
      this is A compnent,
      <button onClick={() => onGetAName(name)}>send</button>
    </div>
  )
}

function B ({ name }) {
  return (
    <div>
      this is B compnent,
      {name}
    </div>
  )
}

function App () {
  const [name, setName] = useState('')
  const getAName = (name) => {
    setName(name)
  }
  return (
    <div>
      this is App
      <A onGetAName={getAName} />
      <B name={name} />
    </div>
  )
}

export default App

  跨层传递

使用的createContext方法创建了一个上下文对象Ctx

顶层组件App通过Ctx.Provider组件提供数据

底层组件B用useContext钩子获取数据

// 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

知识点6.副作用管理器 useEffect

用于Ajax请求 更改Dom操作等

在组件渲染完成后会从服务端获取数据并显示到页面

useEffect(()=>{},[])

import { useEffect, useState } from "react"

function Son () {
  // 1. 渲染时开启一个定时器
  useEffect(() => {
    const timer = setInterval(() => {
      console.log('定时器执行中...')
    }, 1000)

    return () => {
      // 清除副作用(组件卸载时)
      clearInterval(timer)
    }
  }, [])
  return <div>this is son</div>
}

function App () {
  // 通过条件渲染模拟组件卸载
  const [show, setShow] = useState(true)
  return (
    <div>
      {show && <Son />}
      <button onClick={() => setShow(false)}>卸载Son组件</button>
    </div>
  )
}

export default App

知识点7.自定义hook实现

自定义hook之前在学爬虫的时候了解过一些,就是自定义函数

// 封装自定义Hook

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

// 解决思路: 自定义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>
  )
}

export default App

规则:只能在组件或者其他自定义hook中实现,不能嵌套在if for 中

知识点8.redux

集中状态管理工具,应该和Vuex和pinia一个东西咯

npm i @reduxjs/toolkit  react-redux 

<button id="decrement">-</button>
<span id="count">0</span>
<button id="increment">+</button>

<script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>

<script>
  // 定义reducer函数 
  // 内部主要的工作是根据不同的action 返回不同的state
  function counterReducer (state = { count: 0 }, action) {
    switch (action.type) {
      case 'INCREMENT':
        return { count: state.count + 1 }
      case 'DECREMENT':
        return { count: state.count - 1 }
      default:
        return state
    }
  }
  // 使用reducer函数生成store实例
  const store = Redux.createStore(counterReducer)

  // 订阅数据变化
  store.subscribe(() => {
    console.log(store.getState())
    document.getElementById('count').innerText = store.getState().count

  })
  // 增
  const inBtn = document.getElementById('increment')
  inBtn.addEventListener('click', () => {
    store.dispatch({
      type: 'INCREMENT'
    })
  })
  // 减
  const dBtn = document.getElementById('decrement')
  dBtn.addEventListener('click', () => {
    store.dispatch({
      type: 'DECREMENT'
    })
  })
</script>
import { createSlice } from '@reduxjs/toolkit'

const counterStore = createSlice({
  // 模块名称独一无二
  name: 'counter',
  // 初始数据
  initialState: {
    count: 1
  },
  // 修改数据的同步方法
  reducers: {
    increment (state) {
      state.count++
    },
    decrement(state){
      state.count--
    }
  }
})
// 结构出actionCreater
const { increment,decrement } = counter.actions

// 获取reducer函数
const counterReducer = counterStore.reducer

// 导出
export { increment, decrement }
export default counterReducer
import { configureStore } from '@reduxjs/toolkit'

import counterReducer from './modules/counterStore'

export default configureStore({
  reducer: {
    // 注册子模块
    counter: counterReducer
  }
})

为react注入store

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
// 导入store
import store from './store'
// 导入store提供组件Provider
import { Provider } from 'react-redux'

ReactDOM.createRoot(document.getElementById('root')).render(
  // 提供store数据
  <Provider store={store}>
    <App />
  </Provider>
)

react组件使用store

修改store数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1793926.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

本地Nginx的安装到使用

借鉴文章 https://blog.csdn.net/weixin_44005802/article/details/135488448 1.官网下载链接&#xff1a;链接: https://nginx.org/en/download.html 2.将下载的zip包解压后&#xff0c;打开D:…\nginx-1.20.2\conf\nginx.conf&#xff0c;修改server为实际配置。 worker_pr…

Vue 封装elementUI的el-popover

1.封装公共组件 <template><div class"confirm-popover disInlineBlock ml10"><el-popover placement"bottom" v-model"visible" :trigger"triggerType"><div class"confirm-popover-popover"><…

分表策略,你真的分对了?

垂直分表方案 表的记录并不多&#xff0c;但是字段却很长&#xff0c;表占用空间很大&#xff0c;检索表的时候需要执行大量的IO&#xff0c;严重降低了性能。这时需要把大的字段拆分到另一个表&#xff0c;并且该表与原表是一对一的关系。 为什么垂直拆分之后查询性能就变快…

ROG CETRA II 降临2代RGB版 使用体验!

现在Type-C接口的设备越来越多&#xff0c;不仅是台式机开始普及&#xff0c;像NUC、笔记本、Switch、安卓手机等也都是Type-C接口了&#xff0c;所以游戏耳机方面也开始迭代。Type-C还有一个好处就是供电足以撑起降噪处理和RGB灯效&#xff0c;你懂的。今天跟大家分享的就是RO…

基于yolov5s的垃圾桶满溢检测 (附数据集与Coovally操作步骤)

本文主要内容:详细介绍了垃圾桶满溢检测整个过程&#xff0c;从创建数据集到训练模型再到预测结果全部可视化操作与分析。 文末有数据集获取方式&#xff0c;请先看检测效果 现状 在当今城市化高速发展的背景下&#xff0c;随着人口密度的增加和垃圾产生量的急剧攀升&#xff…

linux线程的同步与互斥

前面我们讲了线程的概念以及如何创建与控制线程&#xff0c;接下来我们来对线程的细节与线程之间的问题进行一些讲解&#xff1b; 1.线程的互斥 互斥就是相互排斥&#xff0c;我们可以理解为对立竞争不相容&#xff1b;线程的互斥则是线程之间在对于临界资源竞争时相互排斥的…

Unity | Shader基础知识(番外:了解内置Shader-Standard<一>)

前言 有粉丝给我说&#xff0c;感觉自己内部自带的Shader都还不知道怎么用&#xff0c;希望我讲一下内置Shader。 那我们就从Standard开始吧&#xff01;~ 一、什么是Standard standard是标准着色器&#xff0c;但标准着色器是什么意思&#xff1f; 官方解释&#xff1a;U…

推荐系统三十六式学习笔记:原理篇.内容推荐06|超越标签的内容推荐系统

目录 为什么要做好内容推荐&#xff1f;内容源内容分析和用户分析内容推荐算法总结&#xff1a; 基于内容的推荐系统&#xff0c;有个误区&#xff0c;衡量其性能优劣&#xff0c;评判标准是标签数量够不够。其实标签只是很小一部分。而且即便是标签&#xff0c;衡量质量的方式…

现在有一个生产计划,甲乙丙3个品类共16个产品,生产时间6天,每天甲品类可以生产1张单,乙3张,丙1张,请用MySQL写出H列的效果

现在有一个生产计划&#xff0c;甲乙丙3个品类共16个产品&#xff0c;生产时间6天&#xff0c;每天甲品类可以生产1张单&#xff0c;乙3张&#xff0c;丙1张&#xff0c;请用MySQL写出H列的效果吗&#xff1f; 最终展示结果要求为&#xff1a; 品类产品生产时间开始生产时间…

Nvidia 目前的市值为 3.01 万亿美元,超过苹果Apple

人工智能的繁荣将英伟达的市值推高到足以使其成为全球第二大最有价值的公司。 英伟达已成为全球第二大最有价值的公司。周三下午&#xff0c;这家芯片制造巨头的市值达到 3.01 万亿美元&#xff0c;领先于苹果公司的 3 万亿美元。 喜好儿网AIGC专区&#xff1a;https://heehe…

一文了解UVLED线光源的应用

在机器视觉系统中&#xff0c;光源作为不可或缺的一部分&#xff0c;能够提高目标成像效果&#xff0c;增强检测效果。光源的选择至关重要&#xff0c;选到不合适的会影响成像及检测效果。针对不同的检测对象,不同的形状光源应运而生。我们来看看最UVLED线光源。 下面以CCS的光…

Linux 36.3 + JetPack v6.0@jetson-inference之目标检测

Linux 36.3 JetPack v6.0jetson-inference之目标检测 1. 源由2. detectnet2.1 命令选项2.2 下载模型2.3 操作示例2.3.1 单张照片2.3.2 多张照片2.3.3 视频 3. 代码3.1 Python3.2 C 4. 参考资料 1. 源由 从应用角度来说&#xff0c;目标检测是计算机视觉里面第二个重要环节。之…

【python/pytorch】已解决ModuleNotFoundError: No module named ‘torch‘

【PyTorch】成功解决ModuleNotFoundError: No module named torch 一、引言 在深度学习领域&#xff0c;PyTorch作为一款强大的开源机器学习库&#xff0c;受到了众多研究者和开发者的青睐。然而&#xff0c;在安装和使用PyTorch的过程中&#xff0c;有时会遇到一些问题和挑战…

安全测试 之 安全漏洞: ClickHiJacking

1. ClickHiJacking 定义 点击劫持&#xff08;Click Jacking&#xff09;是一种视觉上的欺骗手段&#xff0c;攻击者通过使用一个透明的iframe&#xff0c;覆盖在一个网页上&#xff0c;然后诱使用户在该页面上进行操作&#xff0c;通过调整iframe页面的位置&#xff0c;可以使…

通用高电子迁移率晶体管(HEMT)的差分微变解算方案及分析型模型

来源&#xff1a;A Difference-Microvariation Solution and Analytical Model for Generic HEMTs&#xff08;TED 22年&#xff09; 摘要 这篇论文提出了一种AlGaN/GaN和AlGaAs/GaAs基高电子迁移率晶体管(HEMT)的分析型直流模型。该模型考虑了高栅偏压下势垒层中积累的电荷。…

Nat Commun|直捣黄龙!空间单细胞组学发现外周血靶细胞亚群的组织落脚点

溃疡性结肠炎&#xff08;Ulcerative colitis&#xff0c;UC&#xff09;是一种慢性炎症性肠道疾病&#xff0c;其特征是免疫介导的黏膜炎症和上皮损伤。目前UC的治疗策略已经从单纯的症状缓解转变为更精准的靶向治疗。Vedolizumab&#xff08;VDZ&#xff09;作为一种抗整合素…

短剧系统源码:打造多平台互动娱乐体验

随着科技的不断进步&#xff0c;多平台互动娱乐体验逐渐成为人们日常生活的一部分。短剧系统源码便是在这样的背景下应运而生&#xff0c;它为开发者提供了一套完整的解决方案&#xff0c;以实现PC端、移动端APP、H5网页以及小程序平台的无缝对接和内容共享。本文将详细介绍短剧…

在iPhone上恢复已删除的Safari历史记录的最佳方法

您是否正在寻找恢复 iPhone 上已删除的 Safari 历史记录的最佳方法&#xff1f;好吧&#xff0c;这篇文章提供了 4 种在有/无备份的情况下恢复 iPhone 上已删除的 Safari 历史记录的最佳方法。现在按照分步指南进行操作。 iPhone 上的 Safari 历史记录会被永久删除吗&#xff1…

开关管的导通损耗和开关损耗及MOS管驱动

导通损耗和开关损耗 开关管的损耗带来的问题 ★使得开关管发热&#xff0c;为了降低温度&#xff0c;需要增大散热面积&#xff0c;从而增大了体积和成本。 ★降低了开关电源的效率。 开关管的损耗分为导通损耗和开关损耗 ★导通损耗&#xff1a;在开关管导通时候&#xf…

重庆耶非凡科技揭秘:海外拼多多选品师岗位真相解析

在当今数字化、全球化的浪潮中&#xff0c;跨境电商行业蓬勃发展&#xff0c;越来越多的企业开始寻求拓展海外市场的新机遇。其中&#xff0c;重庆耶非凡科技有限公司作为一家在软件开发和技术服务领域具有深厚实力的企业&#xff0c;其海外拼多多选品师这一职位引发了广泛关注…