MST

星途 面试题库

面试题:React 跨路由数据共享之高级难度:Redux 与 React - Router 结合

假设你正在开发一个使用 React - Router 的复杂单页应用,需要在不同路由组件间共享用户登录状态等数据。请阐述如何将 Redux 与 React - Router 结合以实现高效的跨路由数据共享,包括 Redux 相关的配置、中间件使用以及 React - Router 与 Redux 交互的关键代码片段。
17.3万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

1. Redux 相关配置

  1. 安装依赖

    npm install redux react - redux
    
  2. 创建 store: 在 src/store.js 文件中:

    import { createStore, applyMiddleware } from'redux';
    import rootReducer from './reducers';
    import thunk from'redux - thunk';
    
    const store = createStore(rootReducer, applyMiddleware(thunk));
    
    export default store;
    

    这里使用了 redux - thunk 中间件,它允许我们在 action 中使用异步操作。

  3. 创建 reducers: 在 src/reducers 目录下创建 userReducer.js 用于管理用户登录状态等数据。例如:

    const initialState = {
        isLoggedIn: false,
        userInfo: null
    };
    
    const userReducer = (state = initialState, action) => {
        switch (action.type) {
            case 'LOGIN_SUCCESS':
                return {
                   ...state,
                    isLoggedIn: true,
                    userInfo: action.payload
                };
            case 'LOGOUT':
                return {
                   ...state,
                    isLoggedIn: false,
                    userInfo: null
                };
            default:
                return state;
        }
    };
    
    export default userReducer;
    

    然后在 src/reducers/index.js 中组合所有 reducers:

    import { combineReducers } from'redux';
    import userReducer from './userReducer';
    
    const rootReducer = combineReducers({
        user: userReducer
    });
    
    export default rootReducer;
    

2. 中间件使用

除了前面提到的 redux - thunk 用于异步操作外,如果项目需要处理副作用(如 API 调用、订阅等),还可以考虑使用 redux - sagaredux - observable

  1. redux - saga 示例: 安装:
    npm install redux - saga
    
    src/store.js 中修改为:
    import { createStore, applyMiddleware } from'redux';
    import rootReducer from './reducers';
    import createSagaMiddleware from'redux - saga';
    import rootSaga from './sagas';
    
    const sagaMiddleware = createSagaMiddleware();
    const store = createStore(rootReducer, applyMiddleware(sagaMiddleware));
    
    sagaMiddleware.run(rootSaga);
    
    export default store;
    
    src/sagas/userSaga.js 中:
    import { call, put, takeEvery } from'redux - saga/effects';
    import { LOGIN_SUCCESS } from '../actions/types';
    import api from '../api';
    
    function* loginUser(action) {
        try {
            const response = yield call(api.login, action.payload);
            yield put({ type: LOGIN_SUCCESS, payload: response.data });
        } catch (error) {
            console.error('Login failed', error);
        }
    }
    
    export function* userSaga() {
        yield takeEvery('LOGIN_REQUEST', loginUser);
    }
    
    src/sagas/index.js 中:
    import { all } from'redux - saga/effects';
    import { userSaga } from './userSaga';
    
    export default function* rootSaga() {
        yield all([userSaga()]);
    }
    

3. React - Router 与 Redux 交互的关键代码片段

  1. 在 React 应用中连接 Redux 和 React - Router: 在 src/index.js 中:
    import React from'react';
    import ReactDOM from'react - dom';
    import { BrowserRouter as Router } from'react - router - dom';
    import { Provider } from'react - redux';
    import store from './store';
    import App from './App';
    
    ReactDOM.render(
        <Provider store={store}>
            <Router>
                <App />
            </Router>
        </Provider>,
        document.getElementById('root')
    );
    
  2. 在路由组件中使用 Redux 数据: 在路由组件(如 src/components/Dashboard.js)中:
    import React from'react';
    import { connect } from'react - redux';
    
    const Dashboard = ({ user }) => {
        return (
            <div>
                {user.isLoggedIn && <p>Welcome, {user.userInfo.name}</p>}
            </div>
        );
    };
    
    const mapStateToProps = state => ({
        user: state.user
    });
    
    export default connect(mapStateToProps)(Dashboard);
    
  3. 通过 Redux 状态影响路由导航: 例如,在登录成功后自动导航到用户仪表盘: 在 src/actions/userActions.js 中:
    import { LOGIN_SUCCESS } from './types';
    import { history } from '../history';
    
    export const login = (credentials) => {
        return async (dispatch) => {
            // 模拟 API 调用
            const response = await fakeLogin(credentials);
            if (response.success) {
                dispatch({ type: LOGIN_SUCCESS, payload: response.data });
                history.push('/dashboard');
            }
        };
    };
    
    这里需要创建一个 history.js 文件用于管理路由历史:
    import { createBrowserHistory } from 'history';
    
    export const history = createBrowserHistory();
    
    然后在 src/index.js 中使用 history 配置 Router
    import React from'react';
    import ReactDOM from'react - dom';
    import { Router } from'react - router - dom';
    import { Provider } from'react - redux';
    import store from './store';
    import App from './App';
    import { history } from './history';
    
    ReactDOM.render(
        <Provider store={store}>
            <Router history={history}>
                <App />
            </Router>
        </Provider>,
        document.getElementById('root')
    );