react 配合vite,利用 import.meta.glob,实现动态路由

react 配合vite,使用 import.meta.glob,实现动态路由

1. 安装必要的库

npm init vite@latest my-react-app --template react
cd my-react-app
npm install
npm install react-router-dom axios
npm install @reduxjs/toolkit react-redux

2. 定义后端接口调用

`// src/api.js
import axios from 'axios';

const api = axios.create({
  baseURL: 'https://your-api-base-url.com',
});

export const login = async (username, password) => {
  const response = await api.post('/login', { username, password });
  return response.data;
};

export const getMenuData = async () => {
  const response = await api.get('/menu');
  return response.data;
};

3. 创建 Redux Store

使用 Redux Toolkit 来创建一个 Redux Store:

// src/store.js
import { configureStore, createSlice } from '@reduxjs/toolkit';

const authSlice = createSlice({
  name: 'auth',
  initialState: {
    isAuthenticated: false,
    menu: [],
  },
  reducers: {
    login: (state, action) => {
      state.isAuthenticated = true;
      state.menu = action.payload.menu;
    },
    logout: (state) => {
      state.isAuthenticated = false;
      state.menu = [];
    },
  },
});

export const { login, logout } = authSlice.actions;
export default configureStore({
  reducer: {
    auth: authSlice.reducer,
  },
});

4. 用户登录并获取菜单数据

创建一个 Login 组件,用于用户登录和获取菜单数据:

// src/pages/Login.jsx
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { login, getMenuData } from '../api';
import { login as loginAction } from '../store';

const Login = () => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const dispatch = useDispatch();
  const history = useHistory();

  const handleLogin = async () => {
    try {
      await login(username, password);
      const menu = await getMenuData();
      dispatch(loginAction({ menu }));
      history.push('/');
    } catch (error) {
      console.error('Login failed', error);
    }
  };

  return (
    <div>
      <h1>Login</h1>
      <input
        type="text"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
        placeholder="Username"
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="Password"
      />
      <button onClick={handleLogin}>Login</button>
    </div>
  );
};

export default Login;

5. 动态生成路由和菜单

使用 import.meta.glob 动态加载组件并生成路由:

// src/App.jsx
import React, { useEffect, useState } from 'react';
import { BrowserRouter as Router, Switch, Route, Redirect } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
import Login from './pages/Login';
import PrivateRoute from './components/PrivateRoute';
import Menu from './components/Menu';
import { getMenuData } from './api';
import { login as loginAction } from './store';

// 动态导入所有页面组件
const modules = import.meta.glob('./pages/*.jsx');

const App = () => {
  const dispatch = useDispatch();
  const isAuthenticated = useSelector((state) => state.auth.isAuthenticated);
  const [routes, setRoutes] = useState([]);

  useEffect(() => {
    const fetchMenuData = async () => {
      const menu = await getMenuData();
      dispatch(loginAction({ menu }));

      const generateRoutes = (menu) => {
        return menu.map((item) => {
          if (item.children) {
            return generateRoutes(item.children);
          }
          const Component = React.lazy(modules[`./pages/${item.component}.jsx`]);
          return {
            path: item.path,
            exact: item.exact,
            component: Component,
          };
        });
      };

      setRoutes(generateRoutes(menu));
    };

    fetchMenuData();
  }, [dispatch]);

  return (
    <Router>
      <Menu />
      <React.Suspense fallback={<div>Loading...</div>}>
        <Switch>
          {routes.map((route, index) => (
            <PrivateRoute
              key={index}
              path={route.path}
              exact={route.exact}
              component={route.component}
            />
          ))}
          <Route path="/login" component={Login} />
          <Redirect to="/" />
        </Switch>
      </React.Suspense>
    </Router>
  );
};

export default App;

6. 创建菜单组件

// src/components/Menu.jsx
import React from 'react';
import { Link } from 'react-router-dom';
import { useSelector } from 'react-redux';

const Menu = () => {
  const menu = useSelector((state) => state.auth.menu);

  const generateMenu = (menu) => {
    return menu.map((item) => {
      if (item.children) {
        return (
          <div key={item.path}>
            <span>{item.title}</span>
            <div>{generateMenu(item.children)}</div>
          </div>
        );
      }
      return (
        <div key={item.path}>
          <Link to={item.path}>{item.title}</Link>
        </div>
      );
    });
  };

  return <div>{generateMenu(menu)}</div>;
};

export default Menu;

7. 创建权限组件

// src/components/PrivateRoute.jsx
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { useSelector } from 'react-redux';

const PrivateRoute = ({ component: Component, ...rest }) => {
  const isAuthenticated = useSelector((state) => state.auth.isAuthenticated);

  return (
    <Route
      {...rest}
      render={(props) =>
        isAuthenticated ? <Component {...props} /> : <Redirect to="/login" />
      }
    />
  );
};

export default PrivateRoute;

8. 创建入口文件

// src/main.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import store from './store';
import './index.css';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

总结

通过以上步骤,我们使用 Vite 作为构建工具,并利用 import.meta.glob 动态导入组件,通过后端接口获取授权菜单数据并在 React 应用中生成动态路由。这样可以根据用户的不同权限进行菜单和路由的动态生成和控制。根据具体需求,可以进一步优化和扩展权限逻辑。

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以回答这个问题。在使用vite搭建React 18应用程序时,可以使用import.meta.glob函数来批量导入组件。这个函数接受一个字符串参数,返回一个promise,可以通过await来等待导入的结果。具体使用方法可以参考vite的官方文档。 ### 回答2: 在使用ViteReact 18时,我们可以使用新的`import.meta.glob`来配置动态导入模块。 `import.meta.glob`是一个自动匹配和导入模块的功能。它允许我们根据指定的匹配模式,动态地导入多个模块。这种导入方式灵活且高效,特别适用于需要动态加载多个模块的场景。 要在Vite中使用`import.meta.glob`,我们需要在项目的`vite.config.js`配置文件中进行相应的设置。 首先,我们需要确保安装了Vite的依赖,包括vite和@vite/react-plugin。 ```shell npm install vite @vite/react-plugin --save-dev ``` 然后,在`vite.config.js`中添加以下内容: ```javascript import reactRefresh from '@vite/react-plugin'; export default { plugins: [ reactRefresh(), ], optimizeDeps: { include: ['react', 'react-dom'], }, }; ``` 接下来,我们可以在React组件中使用`import.meta.glob`来动态地导入多个模块。 ```javascript const pages = import.meta.glob('./pages/*.js'); function App() { return ( <div> {Object.keys(pages).map((path) => { const PageComponent = pages[path]().default; return <PageComponent key={path} />; })} </div> ); } ``` 上述代码示例中,我们使用`import.meta.glob`动态地导入了某个目录下的所有`.js`文件,并渲染每个导入的组件。 这样,我们就可以利用ViteReact 18中的`import.meta.glob`功能来实现动态导入和渲染多个模块的需求。这种方式不仅简洁高效,还能提高开发效率。 ### 回答3: 在使用React 18配置import.meta.glob时,我们需要确保项目中已经升级到React 18版本,并且已经支持相关的API。 首先,我们需要在项目中的vite.config.js文件中配置相关内容。假设我们要匹配以".jsx"和".js"结尾的所有文件,我们可以使用import.meta.glob模式来快速导入这些文件。 ``` import { defineConfig } from 'vite'; export default defineConfig({ ... plugins: [ ... reactRefresh(), { name: 'import-meta-glob', enforce: 'pre', resolveId(source, importer) { if (source.startsWith('/dir/')) { const glob = source.replace('/dir/', '/dir/**/*'); return glob; } return null; }, load(id) { if (id.match(/\.jsx?$/)) { // 加载我们匹配到的文件 return fs.promises.readFile(id, 'utf-8'); } return null; }, }, ... ], ... }); ``` 在这个示例中,我们定义了一个插件名为import-meta-glob,并且在resolveId函数中进行了匹配路径的处理。当路径以"/dir/"开头时,我们将使用import.meta.glob模式匹配所有后缀为".jsx"和".js"的文件。 然后,在load函数中,我们加载匹配到的文件内容。你可以根据自己的需求,使用不同的处理方式来处理这些文件。 最后,在项目中可以直接使用import来引入匹配到的文件,例如: ``` import files from '/dir/*.js'; console.log(files); ``` 这样,我们就成功地在React 18项目中配置了import.meta.glob,可以方便地批量导入文件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值