React+Redux登录后自动切换组件失效问题求助
Let's work through why your component isn't switching automatically after login and fix it step by step.
What's Going Wrong
Let's break down the key issues in your current code:
- Mismatched state types & incorrect checks: Your reducer initializes
useras an empty array[], but sets it to a token string on login success. IncomponentWillReceiveProps, you checknextProps.user.length— while strings do have a length property, this creates confusion, and you don't need to rely on Chrome Storage right after login (Redux already has the token once login succeeds). - Redundant local state: Maintaining
hasTokenin your parent component creates a second source of truth separate from Redux, which leads to sync issues when Redux updates but your local state doesn't catch it properly. - Outdated lifecycle method:
componentWillReceivePropsis deprecated in React. Even if you needed to sync state from props,componentDidUpdateis the modern replacement.
Fixed Solution
Let's rewrite the code to fix these issues:
Step 1: Clean Up the Reducer
First, fix the initial state to avoid type confusion (use null instead of an array for user):
const initialState = { fetching: false, error: null, user: null // Changed from empty array to null } function loginReducer(state=initialState, action) { switch (action.type) { case LOGIN: return {...state, fetching: true} case LOGIN_SUCCESS: return {...state, fetching: false, user: action.data.access_token} case LOGIN_FAILURE: return {...state, fetching: false, error: action.error, user: null} // Reset user on failure default: return state; } }
Step 2: Simplify the Parent Component
Remove the redundant local state dependency and use Redux as your single source of truth. We'll only use Chrome Storage for persistence after page refreshes:
const mapStateToProps = state => { return { userToken: state.loginReducer.user, isFetching: state.loginReducer.fetching } } class App extends React.Component { state = { storedToken: null } componentDidMount() { // Check Chrome Storage only for initial page load (refresh scenario) window.chrome.storage.sync.get(['user_token'], result => { if (result.user_token) { this.setState({ storedToken: result.user_token }) } }) } componentDidUpdate(prevProps) { // Sync new token to Chrome Storage when Redux updates if (prevProps.userToken !== this.props.userToken && this.props.userToken) { window.chrome.storage.sync.set({user_token: this.props.userToken}) } } anotherComponent() { return ( <div className="content"> component to show when the user logs in </div> ) } render() { // Check both Redux state and stored token for login status const isLoggedIn = !!this.props.userToken || !!this.state.storedToken; const { isFetching } = this.props; return ( <div> <Header /> {isFetching ? ( <div>Logging in...</div> ) : ( !isLoggedIn ? <Login /> : this.anotherComponent() )} </div> ) } } export default connect(mapStateToProps, null)(App);
Step 3: Ensure Your Login Action Works Correctly
Make sure your login action creator properly fetches the token and dispatches loginSuccess (assuming you're using redux-thunk or similar middleware):
export const login = (userData) => async (dispatch) => { dispatch({ type: LOGIN }); try { const response = await fetch('/your-login-api-endpoint', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(userData) }); const data = await response.json(); dispatch(loginSuccess(data)); // data should contain the access_token } catch (error) { dispatch(loginFailure(error.message)); } }
Key Improvements
- Single Source of Truth: Redux holds the login state immediately after success, with Chrome Storage only used for persistence.
- Modern Lifecycle: Uses
componentDidUpdateinstead of the deprecatedcomponentWillReceivePropsto react to prop changes. - Clearer State Checks: No more confusion between arrays and strings for user data.
- Loading Feedback: Added a loading state so users know the login is in progress.
内容的提问来源于stack exchange,提问作者justforp basnet
相关产品推荐
相关产品推荐

