reac18 和react-router-dom6 redux8在项目中的使用及部分知识累积

跨域

地址creat-react-app.dev/doc
安装:npm install http-proxy-middleware --save
创建src/setupProxy.js
如果报错记得重启应用。

const {
    
     createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function (app) {
    
    
    app.use(
        '/api',//接口前缀
        createProxyMiddleware({
    
    
            target: 'https://i.maoyan.com',//需要转发到的地址
            changeOrigin: true,
        })
    );
};

路由v6

全局使用:在index.js
引入HashRouter 或者BrowserRouter包裹App

import React from 'react';
import ReactDOM from 'react-dom/client';
import {
    
     HashRouter as Router } from 'react-router-dom'

import './index.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  <Router>
    <App />
  </Router>
);

不使用路由表

创建router/router.js文件,写所有的路由
注意:
重定向:<Route path="*" element={<Navigate to="/" />}></Route>

import React from 'react'
import {
    
     Route, Routes, Navigate } from 'react-router-dom'
import Login from '../views/login/Login'
import NewsSandBox from '../views/sandbox/NewsSandBox'
import Home from '../views/sandbox/home/Home'
import RightList from '../views/sandbox/rightList/RightList'
import RoleList from '../views/sandbox/roleList/RoleList'
import UserList from '../views/sandbox/userList/UserList'
export default function router() {
    
    
    return (
        <Routes>
            <Route path="/sandbox" element={
    
    <NewsSandBox />}></Route>
            <Route path='/login' element={
    
    <Login />} > </Route>
            {
    
    /* 重定向 */}
            <Route path="*" element={
    
    <Navigate to="/" />}></Route>
            <Route path="/home" element={
    
    <Home />}></Route>
            <Route path="/user-manage/list" element={
    
    <UserList />}></Route>
            <Route path="/user-manage/role/list" element={
    
    <RoleList />}></Route>
            <Route path="/user-manage/right/list" element={
    
    <RightList />}></Route>
        </Routes>
    )
}

app.js中引入
<Router></Router>注册路由
在页面中使用Outlet作为路由出口,和vueRouter的router-view其实差不多,都是一个占位符的形式


import Router from "./router/router";
import {
    
     Link } from "react-router-dom";
function App() {
    
    
  return (
    <div >
      <Link to='/'> </Link>
      <Link to='/login'> </Link>
      <Link to='/sandbox'> </Link>
      <Router></Router>
    </div>
  );
}

export default App;

使用路由表

同样文件
配置为数组,导出
重定向 element: <Navigate to='/login' />

import React from 'react'
import {
    
     Navigate } from 'react-router-dom'
import Login from '../views/login/Login'
import NewsSandBox from '../views/sandbox/NewsSandBox'
import Home from '../views/sandbox/home/Home'
import RightList from '../views/sandbox/rightList/RightList'
import RoleList from '../views/sandbox/roleList/RoleList'
import UserList from '../views/sandbox/userList/UserList'
const routes = [
    {
    
    
        path: '/',
        element: <Navigate to='/login' />,
    },
    {
    
    
        path: "/login",
        element: <Login />
    },
    {
    
    
        path: "/home",
        element: <Home />
    },
    {
    
    
        path: "/user-manage",
        element: <NewsSandBox />,
        children: [
            {
    
    
                path: "/user-manage/list",//list
                element: <UserList />
            },
            {
    
    
                path: "/user-manage/role/list",//role/list
                element: <RoleList />
            },
            {
    
    
                path: "/user-manage/right/list",//right/list
                element: <RightList />
            },
        ]
    }
]
export default routes

app.js中引入
使用useRoutes 并将结果放在组件中返回。

import Router from "./router/router";
import {
    
     useRoutes } from "react-router-dom";
import {
    
     Link } from "react-router-dom";
function App() {
    
    
  const element = useRoutes(Router)
  return (
    < >
      {
    
    element}
    </>
  );
}

export default App;

在想要路由出现的地方使用Outlet

import React from 'react'
import {
    
     Outlet} from 'react-router-dom'
import SideMenu from '../../components/sandbox/SideMenu'
import TopHeader from '../../components/sandbox/TopHeader'
export default function NewsSandBox() {
    
    
    return (
        <div>
            <SideMenu></SideMenu>
            <TopHeader></TopHeader>
            <Outlet/>
        </div>
    )
}

路由懒加载

使用const Name =lazy(()=>import('地址'))的方式引入
index.js使用Suspense包裹<App>,否则切换路由时出现报错的问题。

import React from 'react'
import {
    
     Navigate } from 'react-router-dom'
import {
    
     lazy } from 'react'
const Login = lazy(() => import("../views/login/Login"));
const NewsSandBox = lazy(() => import("../views/sandbox/NewsSandBox"));
const Home = lazy(() => import("../views/sandbox/home/Home"));
const RightList = lazy(() => import("../views/sandbox/roleList/RoleList"));
const RoleList = lazy(() => import("../views/sandbox/roleList/RoleList"));
const UserList = lazy(() => import("../views/sandbox/userList/UserList"));
const routes = [
    {
    
    
        path: '/',
        element: <Navigate to='/login' />,
    },
    {
    
    
        path: "/login",
        element: <Login />
    },
    {
    
    
        path: "/home",
        element: <Home />
    },
    {
    
    
        path: "/user-manage",
        element: <NewsSandBox />,
        children: [
            {
    
    
                path: "list",
                element: <UserList />
            },
            {
    
    
                path: "role/list",
                element: <RoleList />
            },
            {
    
    
                path: "right/list",//或者"/user-manage/right/list"
                element: <RightList />
            },
        ]
    }
]
export default routes

不知道为什么使用:

下面两种就会报错(react-router-domv6.14版本),官网也是这样写的。如果有小伙伴知道还望告知!谢谢

   async lazy() {
    
    
             let {
    
     Login } = await import("../views/login/Login");
             return {
    
     Component: Login };
           }
   或者
   component:lazy(() => import("../views/login/Login"))

路由跳转

  1. 使用Link或者NavLink
<Link to="/home"></Link> 
  1. navigate() 路由跳转,编程式跳转
import {
    
     useNavigate } from "react-router-dom";
 export default function SideMenu() {
    
    
  const nagetive = useNavigate()
  const clickMenu = () => {
    
    
    nagetive('/user-manage/list')
  }
  
  return (
      <div className="demo-logo-vertical" onClick={
    
    clickMenu}></div>
  )
}

navigate(path,{replace: true}) 路由跳转,清除历史记录

3.navigate(num) 路由跳转,前进、后退

// 历史记录 前进
navigate(1)

// 历史记录 后退
navigate(-1)

// 历史记录 后退两步
navigate(-2)

路由传参

?传参

navigate(`/news-manage/preview?id=${
      
      item.id}`)

路由页面使用useSearchParams获取参数

/ 拼接

需要与路由定义配合,可多个拼接

navigate(`/news-manage/preview/${
      
      item.id}`)

 {
    
    
      path: 'preview/:id',
      element: <PreviewNew />,
  },

路由页面通过useParams获取参数,返回的key值为path定义时的key值
在这里插入图片描述

声明式导航传值

 <Link to="/news-manage/preview" state={
    
    {
    
    id:item.id,type:'9'}}>点击跳转到</Link>

在路由页面使用useLocation获取参数

const loction = useLocation()

在这里插入图片描述

编程式导航传值

import {
    
     useNavigate } from 'react-router-dom';
const navigate =useNavigate()
navigate(`/news-manage/preview`,{
    
    replace:false,state:{
    
    id:item.id,type:"9"}})

在路由页面使用useLocation获取参数,同上

路由hooks

useLocation

获取当前的loaction对象,包含当前页面的路径和其他信息
在这里插入图片描述

useNavigate

获取导航函数,用于编程式导航

import {
    
     useNavigate } from 'react-router-dom';

function MyComponent() {
    
    
  const navigate = useNavigate();

  function handleClick() {
    
    
    navigate('/dashboard');
  }

  return <button onClick={
    
    handleClick}>Go to Dashboard</button>;
}

useSearchParams

包含一个路径参数的对象,和改变路径参数的方法,仅仅只能用于?传参的形式
想获取路径参数上具体某一个参数的值,必须通过get,传入具体的key,获取value
判断参数存不存在:searchParams.has("id")
修改路径参数:setSearchParams({"id":2})

import {
    
     useSearchParams} from 'react-router-dom';

function MyComponent() {
    
    
   const [searchParams, setSearchParams] = useSearchParams()
  useEffect(() => {
    
    
    console.log(searchParams.get('id'))
  }, [])
  return <div></div>;
}```


获取当前路由的参数,仅用于`path?name=''`等格式,即?
### useParams
获取当前路由的参数
```js
import {
    
     useParams } from 'react-router-dom';

function MyComponent() {
    
    
  const {
    
     id } = useParams();

  return <div>Current ID: {
    
    id}</div>;
}

useMatch

获取当前路由匹配的信息,可以用来判断当前路由是否匹配指定的路径。

import { useMatch } from 'react-router-dom';

function MyComponent() {
  const match = useMatch('/dashboard');

  return <div>Is Match: {match ? 'Yes' : 'No'}</div>;
}

解决闪屏的问题

因为我将整个app.js放在了Suspense中,所以切换的时候出现白色闪屏的情况,将Suspense移动到主框架路由出口即可。

json-server

全局安装cnpm i --save json-server
使用命令json-server --watch .\test.json --port 8000 启动test.json文件,注意每条数据要有id

{
    
    
    "posts": [
        {
    
    
            "id": 1,
            "name": "hyc",
            "url": "---"
        }
    ],
    "comments": [
        {
    
    
            "id": 1,
            "content": "json-server",
            "postId": 1//跟post的id是关联的,用于关联查询
        }
    ]
}

启动结果:
在这里插入图片描述

在页面使用方法:

   //获取
    axios.get("http://localhost:8000/posts").then(res => {
    
    
      console.log(res.data, 'res')
    })

    // 增
    axios.post("http://localhost:8000/posts", {
    
    
      "id": 2,
      "name": "jwj",
      "url": "123"
    })

    // 修改,地址后面添加id,替换除了id之外的内容
    axios.put("http://localhost:8000/posts/2", {
    
    
      "url": "183"
    })

    //更新,只更新对应的值
    axios.patch("http://localhost:8000/posts/2", {
    
    
      "url": "183"
    })

    //删除
    axios.delete("http://localhost:8000/posts/2")
    
   //联合查询 _embed  向下查找
    axios.get("http://localhost:8000/posts?_embed=comments").then(res => {
    
    
      console.log(res.data, 'res')
    })

    //_expand 向上查找,注意使用的时候_expand后跟的去掉s
    axios.get("http://localhost:8000/comments?_expand=post").then(res => {
    
    
      console.log(res.data, 'res')
    })

传值

父组件传值给子组件

Props

Props 属性传递:父组件可以通过 props 将数据传递给子组件。在父组件中,将需要传递给子组件的数据作为属性传递给子组件,在子组件中通过 props 对象访问这些数据。

在父组件中:

function ParentComponent() {
    
    
  const data = 'Hello, child!';
  return <ChildComponent message={
    
    data} />;
}

在子组件中:

function ChildComponent(props) {
    
    
  return <div>{
    
    props.message}</div>;
}

Context 上下文传递

使用 React 的 Context API 可以在父组件和多层嵌套的子组件之间共享数据,而无需手动通过 props 逐层传递。

首先,在父组件中创建一个 Context:

const MyContext = React.createContext();
然后,在父组件中设置要共享的数据:
function ParentComponent() {
    
    
  const data = 'Hello, child!';

  return (
    <MyContext.Provider value={
    
    data}>
      <ChildComponent />
    </MyContext.Provider>
  );
}

最后,在子组件中通过 Consumer 或 useContext 来获取共享的数据:

function ChildComponent() {
    
    
  const message = React.useContext(MyContext);

  return <div>{
    
    message}</div>;
}

状态管理库

使用状态管理库:如果应用中有复杂的状态共享需求,可以考虑使用像 Redux、MobX 或者 Recoil 这样的状态管理库。这些库提供了全局状态存储和更新机制,可以在任意组件之间共享数据。

子组件传值给父组件

在父组件中定义一个回调函数,并将该函数作为 props 传递给子组件:

function ParentComponent() {
    
    
  const handleDataFromChild = (data) => {
    
    
    // 处理从子组件传递过来的数据
    console.log(data);
  };

  return <ChildComponent sendDataToParent={
    
    handleDataFromChild} />;
}

在子组件中,通过调用父组件传递过来的回调函数,将需要传递给父组件的数据作为参数传递:

function ChildComponent(props) {
    
    
  const sendData = () => {
    
    
    const data = 'Hello, parent!';
    props.sendDataToParent(data);
  };

  return (
    <div>
      <button onClick={
    
    sendData}>传递数据给父组件</button>
    </div>
  );
}

在子组件中,可以通过调用 props.sendDataToParent 方法将数据传递给父组件的回调函数。父组件中的回调函数会接收到子组件传递过来的数据,并可以在回调函数中进行相应的处理。

这是一种常见的子组件向父组件传递值的方式,但也可以根据具体需求选择其他方法,比如使用全局状态管理库或者使用 useContext 钩子等。

回显html

不合时宜的使用 innerHTML 可能会导致 cross-site scripting (XSS) 攻击。 净化用户的输入来显示的时候,经常会出现错误,不合适的净化也是导致网页攻击的原因之一。dangerouslySetInnerHTML 这个 prop 的命名是故意这么设计的,以此来警告,它的 prop 值( 一个对象而不是字符串 )应该被用来表明净化后的数据。

  <div dangerouslySetInnerHTML={
     
     {
     
      __html: newsData.content }} style={ 
        { 
         border: "1px solid #ccc" }} />

redux

redux报错

报错

The slice reducer for key “CollapsedReducer” returned undefined during
initialization. If the state passed to the reducer is undefined, you
must explicitly return the initial state. The initial state may not be
undefined. If you don’t want to set a value

在这里插入图片描述
原因是:

  • reducer没有给与返回值;
  • reducer如果没有返回值可以给null,不要给undefined

redux基本使用

安装:

npm i redux react-redux --save

1.创建store

创建/redux/store.js
在store.js文件中,可以有多个文件,使用combineReducers组合
注意使用的是v8版本所以,引入的是legacy_createStore

import {
    
     legacy_createStore as createStore, combineReducers } from "redux";
import CollapsedReducer from "./reducers/Collpased"

const reducer = combineReducers({
    
    
    CollapsedReducer
})
const store = createStore(reducer)
export default store;

Collpased.js文件

const CollapsedReducer = (preState = {
     
      isCollapesd: false }, action) => {
    
    
    let {
    
     type } = action
    switch (type) {
    
    
        case "change_collapsed":
            let newSate = {
    
     ...preState }
            newSate.isCollapesd = !newSate.isCollapesd
            return newSate
        default:
            return preState
    }

}
export default CollapsedReducer

index.js中引入Provider包裹

import React from 'react';
import ReactDOM from 'react-dom/client';
import {
    
     HashRouter as Router } from 'react-router-dom'
import './index.css';
import App from './App';
import './utils/http'
import {
    
     Provider } from "react-redux"
import store from "../src/redux/store"

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  <Provider store={
    
    store} >
  <Router>
      <App />
  </Router>
  </Provider>
);

2.实际使用

在组件中使用

在js文件中使用

在导出时使用connect包裹整个组件,connect第一个括号内进行传参

const state=需要的redux中的值,需要返回一个对象
const type=给一个类型标识,在redux中接收用于区分该做什么处理
export default connect(state,type)(MyComponent)

import {
    
     connect } from "react-redux";

function MyComponent(props){
    
    
//props中可以接收到isCollapesd 
}
const mapStateToProps = ({
     
      CollapsedReducer: {
     
      isCollapesd } }) => {
    
    
  return {
    
     isCollapesd }
}
const mapDispatchToProps = {
    
    
  changeCollapsed() {
    
    
    return {
    
    
      type: "change_collapsed"

    }
  }
}
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent)  //

如果不进行第二个方法传参,如下,接收到dispatch方法,在调用的地方直接调用dispatch进行传参也可以。

,

function MyComponent(props){
    
    
//props中可以接收到isCollapesd 
return(
 <button onClick={
    
    () => props.dispatch(  {
    
    type:"change_collapsed"})}>点击</button>
 )
}
export default connect(
  ({
     
      CollapsedReducer: {
     
      isCollapesd } }) => {
    
     return {
    
     isCollapesd } }
)(MyComponent)

redux持久化(redux-persist)

安装:

cnpm i redux-persist --save

store.js更改为

import {
    
     legacy_createStore as createStore, combineReducers } from "redux";
import CollapsedReducer from "./reducers/Collpased";
import LoadingReducer from "./reducers/Loading.js";
import {
    
     persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'

const persistConfig = {
    
    
    key: 'root',  //在localStorge中生成key为root的值
    storage,
    blacklist: ['LoadingReducer'],  //设置某个reducer数据不持久化,
    // whitelist:['CollapsedReducer'],//设置某个reducer数据持久化
}
const reducer = combineReducers({
    
    
    CollapsedReducer,
    LoadingReducer
})
const myPersistReducer = persistReducer(persistConfig, reducer)

const store = createStore(myPersistReducer)
const persistor = persistStore(store)
export {
    
     store, persistor };

index.js中也需要引入PersistGate和store导出的persistor

import React from 'react';
import ReactDOM from 'react-dom/client';
import {
    
     HashRouter as Router } from 'react-router-dom'
import './index.css';
import App from './App';
import './utils/http'
import {
    
     Provider } from "react-redux"
import {
    
     store,persistor } from "../src/redux/store"
import {
    
     PersistGate } from 'redux-persist/integration/react'
const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  <Provider store={
    
    store} >
    <PersistGate loading={
    
    null} persistor={
    
    persistor}>
      <Router>
        <App />
      </Router>
    </PersistGate>
  </Provider>
);

猜你喜欢

转载自blog.csdn.net/Pure_White520/article/details/131839421