react项目--博客管理

文章目录

  • 技术栈
  • 登录存信息
  • 配置token
  • hooks使用
  • 路由配置
  • 各页面技术总结
    • 首页
    • 发布文章
    • 文章详情页
  • 个人主页
  • 分类页

本篇文章总结一个开发的react项目—博客系统

技术栈

React、react-redux、react-router 6,Ant Design,es6,sass,webpack

登录存信息

在这里插入图片描述

主要业务逻辑:redux存信息
redux如何使用,可以看这篇博客 redux使用
创建一个store文件夹
在这里插入图片描述
在index.js文件夹里面写总代理

import { configureStore } from "@reduxjs/toolkit"; // configureStore (): 包装 createStore 以提供简化的配置选项和良好的默认设置。它可以自动组合你的slice reducers,添加你提供的任何 Redux 中间件,默认包括 Redux-thunk,并启用 Redux DevTools 扩展。
import userReducer from "./modules/user";

export default configureStore({
    reducer:{
        user:userReducer
    }
})

在user.js里面写用户的状态管理

首先导入createSlice,用于接受 reducer 函数的对象、片名和初始状态值,并自动生成带有相应动作创建器和动作类型的 slice reducer。

import { createSlice } from "@reduxjs/toolkit";
import { setToken as _setToken,getToken, removeToken } from "@/utils";
import { loginAPI,getProfileAPI } from "@/apis/user"; //导入需要的其他api

const userStore = createSlice({
}),在createSlice写主要逻辑
定义数据状态

 initialState:{
        token:getToken() || '',
        userInfo:{}
    },

编写reducer逻辑

reducers:{
        setToken(state,action){
            state.token = action.payload

            _setToken(action.payload)
            //action.payload是这个action重新包装后的return返回结果,是createSlice特有的
        },
        setUserInfo(state,action){
            state.userInfo=action.payload
        },
        clearUserInfo(state){
            state.token = ''
            state.userInfo = {}
            removeToken()
        } 
    }
//解构出actionCreater
const { setToken,setUserInfo,clearUserInfo } =userStore.actions

调用接口,获取数据

//异步请求

const fetchLogin = (loginForm) =>{
 return async (dispatch)=>{
    const res = await loginAPI(loginForm)
    dispatch(setToken(res.data.token))
 }
}
//....其余获取个人信息的相关接口

导出reducer函数和封装的函数

//获取reducer函数
const userReducer = userStore.reducer

export {setToken,fetchLogin,fetchUserInfo,clearUserInfo}

export default userReducer

完整的redux就是这些了

配置token

在专门文件里面封装token配置

在这里插入图片描述

//封装token方法

const TOKENKEY='token_key'

function setToken(token){
    localStorage.setItem(TOKENKEY,token)
}

function getToken(){
    return localStorage.getItem(TOKENKEY)
}

function removeToken(){
    localStorage.removeItem(TOKENKEY)
}



export{
    setToken,
    getToken,
    removeToken
}

hooks使用

详细hooks可看这篇文章:react—hooks

获取列表示例,展示如何使用hooks

//获取频道列表的逻辑
import { useState,useEffect } from "react"
import { getChannelAPI }from '@/apis/article'


function useChannel(){
    const [channelList, setChannels] = useState([])

    // 调用接口
    useEffect(() => {
      const getChannelList = async () => {
        const res = await getChannelAPI()
        setChannels(res.data.channels)
  
      }
      getChannelList()
  
    }, [])
    return {channelList}
}

export {useChannel}

路由配置

配置路由守卫,无token信息跳转登录页

import { getToken } from '@/utils'
import { Navigate } from 'react-router-dom'

const AuthRoute = ({ children }) => {
  const isToken = getToken()
  if (isToken) {
    return <>{children}</>
  } else {
    return <Navigate to="/login" replace />
  }
}

export default AuthRoute

基本路由配置

import AuthRoute from "@/components/AuthRoute";

import { Suspense, lazy } from "react";
//<Suspense> 允许在子组件完成加载前展示后备方案。lazy 就是懒加载
import { createBrowserRouter } from "react-router-dom"; //创建路由
//createBrowserRouter底层是用到了h5的新特性history,这个方法可以实现修改地址栏地址而不会向后端发起请求,并且history这个对象本身就提供了很多控制页面跳转,前进后退等方法。而createHashRouter则是利用了锚点跳转不发起请求的特点,也就是你在网络地址后面加 上#,#后面的内容无论怎么改变都不会引起浏览器发起网络请求,然后通过监听onhashchange事件来监听这个锚点的变化,以此来匹配配置的路由。

//路由懒加载
const Home = lazy(()=>import('@/pages/Home'))
const Acticles = lazy(()=>import('@/pages/Acticles'))
//....其余路由



```javascript
const router= createBrowserRouter([
    {
        path:"/",
        element:<AuthRoute> <Layout/> </AuthRoute>,// 路由守卫嵌套
        children:[
            {
                path:'all',
                element:<Suspense fallback={'加载中'}><Home/></Suspense>,
                children:[
                    {
                        index:true, //默认加载路由
                        element:<Suspense fallback={'加载中'}><All/></Suspense> 
                    }, ...........其余配置

在页面设置路由出口

import { Outlet } from 'react-router-dom'
<div style={{backgroundColor:'white'}}>
        <Menu
            mode="horizontal"
            selectedKeys={selectkey}
            onClick={onMenuClick}
            items={items}
            ></Menu>
            <Outlet></Outlet> //设置子路由出口
 </div>)

各页面技术总结

首页

利用useLocation进行反向高亮

 //反向高亮
  const location = useLocation();
  const selectkey  =location.pathname


//触发个人信息的action

 const dispatch = useDispatch()
  useEffect(()=>{
    dispatch(fetchUserInfo())
  },[dispatch])
//获取store内的个人信息
  const name= useSelector(state=>state.user.userInfo.name)

在这里插入图片描述
选择时,高亮效果没实现,增加以下两行代码

const isHomeSelected = location.pathname.startsWith('/all');
selectedKeys={[isHomeSelected ? '/all' : selectkey]}

发布文章

回填数据

const [searchParams]=  useSearchParams()
  const articleId  =searchParams.get('id')
  // console.log(articleId);
  const [form]= Form.useForm()
  useEffect(()=>{
    //通过id获取数据
   async function getArticleDetail(){
    const res=  await getArticleById(articleId)
    const data = res.data
    form.setFieldsValue({...data,
    type:data.cover.type,
    })
    //回填图片列表
    setImageType(data.cover.type)
    setImageList(data.cover.images.map(url=>{
      
      return {url}
    }))
   }
   //只有有id才能回填
   if(articleId){
    getArticleDetail()
   }
   
  },[articleId,form])

文章详情页

在这里插入图片描述
内容是html形式,转化为文本类型,封装了一个函数

 function removeHTMLTags(html) {
    const doc = new DOMParser().parseFromString(html, 'text/html');
    return doc.body.textContent || '';
  }

个人主页

在这里插入图片描述
先调用redux里面的方法 ,获取个人信息

useEffect(() => {
    dispatch(fetchUserInfo());
  }, [dispatch]);

问题:由于使用了一次useEffect,当页面再次渲染时,数据回填不上
解决方法:
进行if判断,有id机进行回填,实现异步操作

useEffect(()=>{
    if (data) {
      //进行数据回填
      form.setFieldsValue({ name, gender: gender === 0 ? '男' : '女', intro });
      //回填照片
      console.log(photo);
      let url = [{
        uid: '-1',
        name: 'image1.png',
        status: 'done',
        url:data.photo,
        description: '这是第一张图片'
      }]
      console.log(url);
      setImageUrl(url)
      
  }},[data])

问题:生日时间第一次获取到null,数据回填成默认形式,不是应有的数据
解决方法:

//在组件内设置key,当key里面值变化时,组件重新渲染
<Form.Item
          label="生日"
        >
          <DatePicker defaultValue={defaultValue} key={defaultValue} onChange={getDate} />
        </Form.Item>

问题:头像设置问题,在有头像时,不显示上传部分
解决方法:

//用三元表达式进行判断
<Upload
               name="avatar"
              listType="picture-circle"
              className="avatar-uploader"
              showUploadList
              action="https://660d2bd96ddfa2943b33731c.mockapi.io/api/upload"
              onChange={onChange}
              maxCount={1}
              fileList={imageUrl}
            >
              {count===0?<div style={{ marginTop: 8 }}>
                <PlusOutlined />
              </div>:''}
            </Upload>

分类页

在这里插入图片描述
由于页面一样,数据不一样,先封装个模板,等待传来的参数
在这里插入图片描述

const Item = (props) => {
    //得到传来的list
    const { parameter } = props;
    // console.log('/',parameter);
    const navigate = useNavigate()
    .....其余代码
    }

问题:分类是根据标签列表实现的,所以要先进行判断,以前端页面举例

const Before=()=>{
 
    const [belist,setBelist] = useState([])
    //判断
    getList().then(res=>{
    let list = res.filter((item)=>{
        return item.channel_id===1 || item.channel_id===6 || item.channel_id===15 || item.channel_id===17 || item.channel_id===23
    })
    setBelist(list)
    })
    
    
    return (
        <div>
        //传参
            <Item parameter= {belist}></Item>
        </div>
    )

}

其他页面类似

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微服务之负载均衡器

1、负载均衡介绍 负载均衡就是将负载(工作任务&#xff0c;访问请求)进行分摊到多个操作单元(服务器&#xff0c;组件)上 进行执行。 根据负载均衡发生位置的不同&#xff0c; 一般分为服务端负载均衡和客户端负载均衡。 服务端负载均衡指的是发生在服务提供者一方&#xff…

AWS S3存储桶中如何下载文件

AWS S3存储桶中如何下载文件 1.单个下载 AWS S3 控制台提供了下载单个文件的功能&#xff0c;但是不支持直接在控制台中进行批量下载文件。您可以通过以下步骤在 AWS S3 控制台上下载单个文件&#xff1a;   1.1登录 AWS 管理控制台。   1.2转到 S3 服务页面。   1.3单击…

使用 C# 学习面向对象编程:第 4 部分

C# 构造函数 第 1 部分仅介绍了类构造函数的基础知识。 在本课中&#xff0c;我们将详细讨论各种类型的构造函数。 属性类型 默认构造函数构造函数重载私有构造函数构造函数链静态构造函数析构函数 请注意构造函数的一些基本概念&#xff0c;并确保你的理解非常清楚&#x…

西门子PLC位逻辑指令学习(SCL语言)

R_TRIG 参数 功能 当CLK信号出现一个低电平到高电平的跳变时&#xff0c;输出Q导通一个周期。 实例 定义以下类型变量 "R_TRIG_DB"(CLK:"data".source,Q>"data".result); //当source输入出现低电平到高电平跳变&#xff0c;result信号…

《Brave New Words 》4.2 AI 与学生心理健康辅导的结合

Part IV Better Together 第四部分 携手共进 AI Meets Student Mental Health Coaching AI 与学生心理健康辅导的结合 Here’s the scenario: You’re minutes away from taking a final exam. You’ve studied, but your heart is racing and your mind has gone blank. Anxie…

MIPI A-PHY协议学习

一、说明 A-PHY是一种高带宽串行传输技术,主要为了减少传输线并实现长距离传输的目的,比较适用于汽车。同时,A-PHY兼容摄像头的CSI协议和显示的DSI协议。其主要特征: 长距离传输,高达15m和4个线内连接器; 高速率,支持2Gbps~16Gbps; 支持多种车载线缆(同轴线、屏蔽差分…

探索C++ STL的设计方式:将算法与数据结构分离

STL的设计 一、简介二、STL容器三、C数组四、用户定义的集合4.1、使用标准集合的typedef4.2、重用标准迭代器4.3、实现自己的迭代器 五、总结 一、简介 本文介绍STL的设计方式&#xff0c;以及如何设计自己的组件&#xff0c;使其能够充分利用STL的功能。 STL的设计旨在将算法…

多目标融合参数搜索

多目标融合 权重分类目人群。 trick normlize 不同Score之间含义、量级和分布差异较大&#xff1a;评分计算的不同部分的意义、范围和分布存在显著差异&#xff0c;这使得直接比较或融合它们的结果变得困难。显式反馈&#xff08;如点赞率&#xff09;存在用户间差异&#…

盘点四家企业软件巨头的Gen AI应用进程

文/明道云创始人任向晖 目前大部份行业分析还聚焦在Open AI&#xff0c;Langchain这些和Generative AI直接相关的企业和产品上。实际上&#xff0c;企业软件市场的感知和行动已经非常迅速。在此项技术进入公众视野18个月后&#xff0c;我们来盘点一下领先的企业软件应用是如何利…

Lua连接Redis客户端执行命令

该示例演示使用Redis连接池&#xff0c;及Redis执行命令与获取返回数据 require("api.website") local dkjson require("api.dkjson")-- 创建连接池 local pool redis_pool.new() -- 置连接池信息 pool:start("127.0.0.1",6379,"998866&…

C语言之argc、argv与main函数的传参

一 &#xff1a;谁给main函数传参 &#xff08;1&#xff09;调用main函数所在的程序的它的父进程给main函数传参&#xff0c;并且接收main函数的返回值 二 &#xff1a;为什么需要给main函数传参 &#xff08;1&#xff09;首先mian函数不传承是可以的&#xff0c;也就是说它的…

字符串拼接之char实现

目录 一、前言 二、memcpy函数用法 三、代码实现 一、前言 c中想到字符串拼接&#xff0c;我们都知道可以用c库中std::string的字符串中的简单加法进行拼接。示例&#xff1a; int main() {std::string str1 "hello";std::string str2 "World";std::…

OpenEuler系统学习

OpenEuler系统简介 什么是OpenEuler&#xff0c;个人理解就是&#xff1a;通过社区合作&#xff0c;打造统一和开放的操作系统。 官方是这么介绍的&#xff1a; 欧拉是数字基础设施的开源操作系统&#xff0c;可广泛部署于服务器、云计算、边缘计算、嵌入式等各种形态设备&a…

Vue 面试通杀秘籍

理论篇&#xff1a; 1. 说说对 Vue 渐进式框架的理解&#xff08;腾讯医典&#xff09; a) 渐进式的含义&#xff1a; 主张最少, 没有多做职责之外的事 b) Vue 有些方面是不如 React&#xff0c;不如 Angular.但它是渐进的&#xff0c;没有强主张&#xff0c; 你可以在原有…

Kimichat使用案例013:用kimichat批量识别出图片版PDF文件中的文字内容

文章目录 一、介绍二、具体操作三、信息识别一、介绍 图片版的PDF文件,怎么才能借助AI工具来提取其中全部的文字内容呢? 第一步:将PDF文件转换成图片格式 具体方法参见文章: Kimichat使用案例011:用kimichat将PDF自动批量分割成多个图片(零代码编程) 第二步:识别图片中…

Redis实战宝典:基础知识、实战技巧、应用场景及最佳实践全攻略

背景 在Java系统实现过程中&#xff0c;我们不可避免地会借助大量开源功能组件。然而&#xff0c;这些组件往往功能丰富且体系庞大&#xff0c;官方文档常常详尽至数百页。而在实际项目中&#xff0c;我们可能仅需使用其中的一小部分功能&#xff0c;这就造成了一个挑战&#…

重庆地区媒体宣传邀约资源整理

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 重庆地区媒体宣传邀约资源整理 一、主流媒体资源 电视台&#xff1a;重庆电视台&#xff1a;作为重庆地区最具影响力的电视媒体之一&#xff0c;拥有多个频道&#xff0c;涵盖新闻、综艺…

第2章 Rust初体验1/8:prelude:简化代码的自动标准库加载:猜骰子冷热游戏

讲动人的故事,写懂人的代码 在跑过Hello world程序后,三个人觉得这样还不过瘾,于是决定把那本Rust书里的猜数字游戏换个新面孔,变成“猜骰子冷热”游戏,然后一起动手实现一下。这样我们就能更深入地体验到Rust编程的乐趣啦。 (顺便说一句,如果你想找这本书的所有代码,…

Sklearn的安装和用法

安装sklearn相对简单&#xff0c;因为它是一个Python库&#xff0c;可以通过Python的包管理器pip来安装。 Windows、macOS和Linux通用步骤&#xff1a; 确保Python已安装&#xff1a; sklearn是基于Python的&#xff0c;所以首先确保你的计算机上安装了Python。推荐使用Pytho…

【图论应用】使用多路图(multigraph)对上海地铁站点图建模,并解决最短路径问题

文章目录 1 前言2 导包导入数据集3 创建多路图&#xff0c;导入节点和边信息3 绘制线路图4 计算最短路径 1 前言 最近正在学习图神经网络&#xff0c;先pick up了一些最基础的图论知识并学习了一些好玩的应用。 本文启发于B站视频&#xff08;BV1LY411R7HJ&#xff09;&#…