做标志的网站,wordpress留言板源码,wordpress禁止访问模版页面,资源库网站开发文章目录 技术栈登录存信息配置tokenhooks使用路由配置各页面技术总结首页发布文章文章详情页 个人主页分类页 本篇文章总结一个开发的react项目—博客系统 技术栈
React、react-redux、react-router 6#xff0c;Ant Design#xff0c;es6#xff0c;sass#xff0c;webp… 文章目录 技术栈登录存信息配置tokenhooks使用路由配置各页面技术总结首页发布文章文章详情页 个人主页分类页 本篇文章总结一个开发的react项目—博客系统 技术栈
React、react-redux、react-router 6Ant Designes6sasswebpack
登录存信息 主要业务逻辑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; //导入需要的其他apiconst 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.userInfoaction.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.reducerexport {setToken,fetchLogin,fetchUserInfo,clearUserInfo}export default userReducer完整的redux就是这些了
配置token
在专门文件里面封装token配置 //封装token方法const TOKENKEYtoken_keyfunction 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/articlefunction 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-domconst 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}}MenumodehorizontalselectedKeys{selectkey}onClick{onMenuClick}items{items}/MenuOutlet/Outlet //设置子路由出口/div)各页面技术总结
首页
利用useLocation进行反向高亮 //反向高亮const location useLocation();const selectkey location.pathname//触发个人信息的actionconst dispatch useDispatch()useEffect((){dispatch(fetchUserInfo())},[dispatch])
//获取store内的个人信息const name useSelector(statestate.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.dataform.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.Itemlabel生日DatePicker defaultValue{defaultValue} key{defaultValue} onChange{getDate} //Form.Item问题头像设置问题在有头像时不显示上传部分 解决方法
//用三元表达式进行判断
UploadnameavatarlistTypepicture-circleclassNameavatar-uploadershowUploadListactionhttps://660d2bd96ddfa2943b33731c.mockapi.io/api/uploadonChange{onChange}maxCount{1}fileList{imageUrl}{count0?div style{{ marginTop: 8 }}PlusOutlined //div:}/Upload分类页 由于页面一样数据不一样先封装个模板等待传来的参数
const Item (props) {//得到传来的listconst { 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_id1 || item.channel_id6 || item.channel_id15 || item.channel_id17 || item.channel_id23})setBelist(list)})return (div//传参Item parameter {belist}/Item/div)}其他页面类似