0

当用户登录时,我想显示用户名并将按钮文本从导航栏(导航组件)中的“登录”更改为“注销”。我厌倦了通过将路由器历史位置推送到用户登录的主页来重新渲染导航组件在。

this.props.history.push('/')

然后用户可以成功登录,用户数据保存在localStorage中,路由器位置发生变化。数据保存在 localStorage 中,但组件不会重新渲染。

这是我尝试过的。

  1. 试图将“connected-react-router”降级为“v6.0.0”,但它给我带来了一些错误。所以把它放回最新版本'^6.4.0'。

  2. 尝试在作为父组件的 App.js 中添加导航栏代码。但是 app.js 本身也不会在用户登录时重新渲染。

应用程序.js

import React from 'react';
import { connect } from 'react-redux';
/* --- Components --- */
import Nav from './src/components/nav';
import Loader from './src/shared/loader';
import './styles/main.scss';

const FlashMessagesContainer = Loader({
  loader: () =>
    import('./src/shared/flassMessagesContainer' /* webpackChunkName: 'FlashMessagesContainer' */),
});

const App = (props, { isOnModal }) => (
  <div id="app">
    <Nav />
    {!isOnModal && (
      <div className="flex justify-center">
        <FlashMessagesContainer />
      </div>
    )}
    {props.children}
  </div>
);

const mapPropsToState = state => ({
  isOnModal: state.modal.show,
});

export default connect(
  mapPropsToState,
  null,
)(App);

导航.js

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link, withRouter } from 'react-router-dom';

/* --- Components --- */
import {
  isLoggedIn,
  getCompanyName,
  clearLocalStorage,
} from '../../localStorage';

class Nav extends Component {

  handleUserLogout = async ev => {
    ev.preventDefault();
    await clearLocalStorage();
    return this.props.history.push('/login');
  };

  render() {
    return (
      <div className="nav">  
          {isLoggedIn() ? (
            <div className="flex">
              <p className="mr3 mt2">
                안녕하세요. <span className="b">{getCompanyName()}</span>
                &#8201;님,
              </p>
              <button
                type="button"
                className="login-btn td-none c-text br f-mini"
                onClick={this.handleUserLogout}
              >
                로그아웃
              </button>
            </div>
          ) : (
            <Link className="login-btn td-none c-text br f-mini" to="/login">
              로그인
            </Link>
          )}
      </div>
    );
  }
}

export default withRouter(Nav);

localStorage.js

export const getToken = () => localStorage.token;
export const getCompanyName = () => localStorage.companyName;
export const isLoggedIn = () => !!localStorage.token;
export const saveUserNameAndToken = userData => {
  localStorage.setItem('token', userData.token);
  localStorage.setItem('companyName', userData.companyName);
};
export const clearLocalStorage = () => localStorage.clear();

index.js

import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter as Router } from 'connected-react-router';
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import configureStore, { history } from './store';
import Routes from './routes';

const theme = createMuiTheme({
 ...
});

const store = configureStore();
const root = document.createElement('div');
document.body.appendChild(root);

render(
  <Provider store={store}>
    <MuiThemeProvider theme={theme}>
      <Router history={history}>
        <Routes />
      </Router>
    </MuiThemeProvider>
  </Provider>,
  root,
);

路由.js

import React from 'react';
import { Switch, Route } from 'react-router-dom';
import { hot, setConfig } from 'react-hot-loader';
import { withRouter } from 'react-router';
/* --- Components --- */
import App from './app';
import Loader from './src/shared/loader';

const Home = Loader({
  loader: () =>
    import('./src/components/home/homeContainer' /* webpackChunkName: 'Home' */),
});

...

const routes = props => (
  <div>
    <App history={props.history} />
    <Switch>
      <Route exact path="/" component={Home} />
      <Route path="/login" render={props => <Login {...props} />} />
      <Route path="/users/account" component={Users} />
      <Route component={NoMatch} />
    </Switch>
  </div>
);

const Routes =
  !module.hot || process.env.NODE_ENV === 'production'
    ? routes
    : hot(module)(routes);

export default withRouter(Routes);

我希望在路由器位置更改时重新渲染 Nav 组件。

react: ^16.8.6
react-dom: ^16.8.6
react-loadable: ^5.5.0
react-redux: ^6.0.0
react-router-dom: ^4.3.1
redux: ^4.0.0
connected-react-router: ^6.4.0
4

1 回答 1

0

我通过在 redux 存储中保存“isLoggedIn”状态来修复它。为了在页面刷新时保持来自 redux 存储的状态,我使用了“redux-persist”。

现在,导航组件在路由器位置更改时重新渲染,并且即使在页面刷新时也会保存用户名数据。

authReducer.js

const initialState = {
  isLoggedIn: false,
  userName: '',
};
const auth = (state = initialState, action) => {
  switch (action.type) {
    case types.USER_LOGIN:
      return {
        ...state,
        isLoggedIn: true,
        userName: action.payload,
      };
    case types.USER_LOGOUT:
      return {
        ...state,
        isLoggedIn: false,
        userName: '',
      };
    default:
      return state;
  }
};

导航.js

...
{this.props.isLoggedIn ? (
           ...
          ) : (
           ...
          )}
...

const mapStateToProps = state => ({
  isLoggedIn: state.auth.isLoggedIn,
  userName: state.auth.userName,
});

const mapDispatchToProps = dispatch => ({
  userLogout: () => dispatch(userLogout()),
});

export default withRouter(
  connect(
    mapStateToProps,
    mapDispatchToProps,
  )(Nav),
);

[ redux-persist 设置 ]

store.js

import { applyMiddleware, createStore } from 'redux';
import thunkMiddleware from 'redux-thunk';
import { createLogger } from 'redux-logger';
import { composeWithDevTools } from 'redux-devtools-extension';
import { routerMiddleware } from 'connected-react-router';
import createBrowserHistory from 'history/createBrowserHistory';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import createRootReducer from './src/reducers';

export const history = createBrowserHistory();

const persistConfig = {
  key: 'root',
  storage,
};
const persistedReducer = persistReducer(
  persistConfig,
  createRootReducer(history), 
);

const store = createStore(
  persistedReducer,
  composeWithDevTools(
    applyMiddleware(
      routerMiddleware(history), 
      thunkMiddleware,
      createLogger({
        predicate: () => process.env.NODE_ENV === 'development',
        collapsed: true,
      }),
    ),
  ),
);

export const persistor = persistStore(store);
export default store;

index.js

import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter as Router } from 'connected-react-router';
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import { PersistGate } from 'redux-persist/lib/integration/react';
import store, { history, persistor } from './store';
import Routes from './routes';
import Loading from './src/shared/loading';

const theme = createMuiTheme({
  palette: {
    primary: { main: '#AE9A65' },
    secondary: { main: '#ee9105' },
    success: { main: '#43A047' },
    warning: { main: '#FFA000' },
    error: { main: '#ed4337' },
    info: { main: '#2196F3' },
  },
});

const root = document.createElement('div');
document.body.appendChild(root);

render(
  <Provider store={store}>
    <PersistGate loading={<Loading />} persistor={persistor}>
      <MuiThemeProvider theme={theme}>
        <Router history={history}>
          <Routes />
        </Router>
      </MuiThemeProvider>
    </PersistGate>
  </Provider>,
  root,
);
于 2019-05-30T04:43:33.647 回答