Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Component wont update, despite not state mutation and proper connect state to props #1046

Closed
jp3492 opened this issue Oct 12, 2018 · 6 comments

Comments

@jp3492
Copy link

jp3492 commented Oct 12, 2018

My header component is not logging my updated auth state after im authenticated

I seem to be doing everything that is required.

I dont mutate my state in the reducer
I connect my state to my Header props
I log this.props in componentWillMount()

but my console will not update my component after auth is set to the received token string

error

any ideas where my bug is? thanks a lot

My index file

import React from 'react'
import ReactDOM from 'react-dom'
import { HashRouter, Route } from 'react-router-dom'

import { Provider } from 'react-redux'
import { createStore, applyMiddleware } from 'redux'
import reduxThunk from 'redux-thunk'
import logger from 'redux-logger'

import {
  App,
  AuthForm
} from './directory'

import reducer from './reducer'

const store = createStore(
  reducer,
  applyMiddleware(reduxThunk, logger)
)

ReactDOM.render(
  <Provider store={store}>
    <HashRouter>
      <App>
        <Route path='/login' component={AuthForm} />
        <Route path='/register' component={AuthForm} />
      </App>
    </HashRouter>
  </Provider>, document.getElementById('root'))

My root reducer

import { combineReducers } from 'redux'

import auth from './app/app.reducer'

const appReducer = combineReducers({
  auth
})

const rootReducer = (state, action) => {
  if (action.type === 'logout') {
    state = undefined
  }
  return appReducer(state, action)
}

export default rootReducer

My header component

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

import { checkToken, logout } from './header.actions'

import { Header, MobileNav, Menu, Banner, MobileBackDrop } from './header.elements'

class header extends Component{
  constructor(props){
    super(props)
    this.state = {
      open: false
    }
  }
  async componentWillMount(){
    const { actions: { checkToken } } = this.props 
    console.log(this.props);
    
    await checkToken()
  }
  menuItems = () => {
    const { auth, actions: { logout } } = this.props
    return [
      { label: 'Login', route: '/login', auth: false },
      { label: 'Register', route: '/register', auth: false },
      { label: 'Profile', route: '/profile', auth: true },
      { label: 'Logout', route: '/', action: logout, auth: true }
    ].filter( i => { return i.auth === (auth !== null) })
  }
  menuClick = async () => {
    const checked = document.getElementById('menu-btn').checked
    await this.setState({ open: !this.state.open })
  }
  menuItemClick = async item => {
    const { route, action } = item
    if (typeof action !== 'undefined') {
      action()
    }
    this.props.history.push(route)
    await this.setState({
      open: false
    })
    document.getElementById('menu-btn').checked = false
  }
  manuBackDropClick = async () => {
    document.getElementById('menu-btn').checked = false 
    await this.setState({ open: false })
  }
  render(){
    const items = this.menuItems()
    return (
      <Header>
        <Banner />
        <MobileNav 
          onClickAction={this.menuClick} 
          />
        {
          this.state.open ?
          <MobileBackDrop 
            breakPoint={768} 
            onClick={this.manuBackDropClick} 
            />: 
          null
        }
        <Menu 
          length={items.length} 
          open={this.state.open} 
          breakPoint={768}
          >
          {
            items.map( i => {
              return (
                <li 
                  onClick={ () => this.menuItemClick(i)}
                  >
                  {i.label}
                </li>
              )
            })
          }
        </Menu>
      </Header>
    )
  }
}

const mapStateToProps = ({ auth }) => {
  return { auth }
}

const mapDispatchToProps = (dispatch) => {
  return { actions: bindActionCreators({ logout, checkToken }, dispatch), dispatch }
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(header))

My header actions

import { tokenName, updateToken } from '../../../token'

import { AUTHENTICATED } from '../authForm/authForm.types'

const checkToken = () => async dispatch => {
  const token = await updateToken()
  dispatch({ type: AUTHENTICATED, payload: token })
}

const logout = () => async dispatch => {
  await localStorage.clear()
  dispatch({ type: 'logout' })
}

export {
  logout,
  checkToken
}

My auth reducer

import {
  AUTHENTICATED
} from './common/authForm/authForm.types'

const INITIAL_STATE = null

export default (state = INITIAL_STATE, action) => {
  const { type, payload } = action
  switch (type) {
    case AUTHENTICATED:
      return payload
    default:
      return state
  }
}

My token functions

import axios from 'axios'

const tokenName = 'token'

const setToken = async value => {
  // await axios.defaults.headers.common['x-access-token'] = value
  await localStorage.setItem(tokenName, JSON.stringify({
    timestamp: Date.now(),
    value
  }))
  return 
}

const updateToken = async token => {
  if (token) {
    await setToken(token)   
    console.log('token set')
  } else {
    const jwt = await localStorage.getItem(tokenName)
    if (jwt) {
      const { value, timestamp } = JSON.parse(jwt) 
      if ((Date.now() - timestamp) > 86400000) {
        await localStorage.clear()
        return null
      } else {
        await setToken(value)
        return value
      }
    } else {
      return null
    }
  } 
  return
}

export {
  tokenName,
  updateToken
}
@timdorr
Copy link
Member

timdorr commented Oct 12, 2018

This is a bug tracker, not a support system. For usage questions, please use Stack Overflow or Reactiflux where there are a lot more people ready to help you out. Thanks!

@timdorr timdorr closed this as completed Oct 12, 2018
@zachwolf
Copy link

While I don't want to encourage using git issues as support, I do want to leave a trail for the next dev that runs into this.

This definitely is a bug. It's been brought up in a few different places, including this ticket.

Our team has been scratching our heads a bit around this same issue. I'm not sure what exactly the breaking change is, but I've created a reduced test case to show the behavior in action.

Broken demo: https://codesandbox.io/s/yw042lwl4j
Working demo: https://codesandbox.io/s/yw042lwl4j

The only difference between the two is the version of react-redux. 5.0.7 works and 5.1.0-test.1 breaks.

With that knowledge I found a big thread discussing this exact behavior.

Short answer fix: make sure you're using a stable release.

@markerikson
Copy link
Contributor

markerikson commented Oct 23, 2018

@zachwolf : yes, 5.1.0-test.1 is absolutely broken, and should not be used.

Since it was a test release, it was something that people had to explicitly choose to install, and so should also have been tried in an experimental branch of your app or something similar.

@zachwolf
Copy link

Thanks @markerikson!

I won't name names, but git blame tells me it was a coworker's fault. 😉

If it's of any value on how it ended up in our codebase, it was suggested as an update from npm-check-updates. Looks like they have an older issue explaining this can happen if beta branches are tagged as latest. I can see that this is not the case with react-redux though:

screen shot 2018-10-23 at 7 19 28 pm

https://www.npmjs.com/package/react-redux?activeTab=versions

@markerikson
Copy link
Contributor

Interesting.

@timdorr , is there any way we can at least remove the next tag from 5.1.0-test.1 ?

@timdorr
Copy link
Member

timdorr commented Oct 24, 2018

Yep, I'll do so when at a computer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants