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

UncontrolledDropdown in 8.0.0 does not find toggle function in this.context #1457

Closed
twheys opened this issue Apr 8, 2019 · 22 comments · Fixed by #1753
Closed

UncontrolledDropdown in 8.0.0 does not find toggle function in this.context #1457

twheys opened this issue Apr 8, 2019 · 22 comments · Fixed by #1753

Comments

@twheys
Copy link

twheys commented Apr 8, 2019

  • components: UncontrolledDrownDown
  • reactstrap version #8.0.0
  • import method umd/csj/es
  • react version #16.4.1
  • bootstrap version #4.3.1

What is happening?

On clicking the dropdown button in the UncontrolledDropdown component, an unhandled exception is raised and the dropdown menu does not appear.

What should be happening?

On clicking the dropdown button, the dropdown menu should appear.

Steps to reproduce issue

  1. Render the UncontrolledDropdown as provided in the docs
  2. Click on the button
  3. Observe that the dropdown menu does not toggle open and that there is an exception in the consolee.

Error message in console

Uncaught TypeError: this.context.toggle is not a function
    at ProxyComponent.onClick (DropdownToggle.js:59)
    at ProxyComponent.onClick (react-hot-loader.development.js:693)
    at ProxyComponent.onClick (Button.js:52)
    at ProxyComponent.onClick (react-hot-loader.development.js:693)
    at HTMLUnknownElement.callCallback (react-dom.development.js:100)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:138)
    at Object.invokeGuardedCallback (react-dom.development.js:187)
    at Object.invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:201)
    at executeDispatch (react-dom.development.js:461)
    at executeDispatchesInOrder (react-dom.development.js:483)
    at executeDispatchesAndRelease (react-dom.development.js:581)
    at executeDispatchesAndReleaseTopLevel (react-dom.development.js:592)
    at forEachAccumulated (react-dom.development.js:562)
    at runEventsInBatch (react-dom.development.js:723)
    at runExtractedEventsInBatch (react-dom.development.js:732)
    at handleTopLevel (react-dom.development.js:4477)

Code

<UncontrolledDropdown>
                <DropdownToggle caret>
                    Dropdown
                </DropdownToggle>
                <DropdownMenu>
                    <DropdownItem header>Header</DropdownItem>
                    <DropdownItem disabled>Action</DropdownItem>
                    <DropdownItem>Another Action</DropdownItem>
                    <DropdownItem divider />
                    <DropdownItem>Another Action</DropdownItem>
                </DropdownMenu>
            </UncontrolledDropdown>
@twheys
Copy link
Author

twheys commented Apr 8, 2019

I've also tested the same example in reactstrap==7.1.0 and get the expected output.

@TheSharpieOne
Copy link
Member

This works with the latest version of react: https://stackblitz.com/edit/reactstrap-v8-6oafs2?file=Example.js

I can confirm that I am gettin the same error when using react@16.4.1. We'll have to look into it.

For now, the suggested workaround is to upgrade react to 16.8 if you can.

@YaroslavLyzlov
Copy link

@twheys Hi, Did you solve the problem? I use react@16.8.6 and reactstrap@8.0.0, but i see this.context.toggle error :(

@Rgstaub
Copy link

Rgstaub commented Apr 15, 2019

I also get this error with react@16.8.6 and reactstrap@8.0.0.

@TheSharpieOne
Copy link
Member

TheSharpieOne commented Apr 24, 2019

It turns about the minimum supported version for the way context is being consumed within DropdownToggle is react 16.6 which would explain why it works in newer version of react and not the 16.4 version reported here.
I know the minimum version of react listed in peerDeps for this project is 16.3, but we will need to bump that (Or change the way we consume the context.). I would prefer to change the way the context is consumed to support a more broad range of react versions (if anyone want to submit a PR).

For everyone reporting this issues while using the latest version of react, please provide an example using stackblitz or something similar as I cannot reproduce it in the latest version of react. (see my sample: stackblitz.com/edit/reactstrap-v8-6oafs2?file=Example.js) Chances are that you are not using the version of react you think you are using.

@leighmetzroth
Copy link

Using your example, I have worked out how to replicate it. It appears to only be an issue if you're importing the DropDownToggle (or DropDownMenu) directly out of the lib folder.

Here is the modified stackblitz with the issue:
https://stackblitz.com/edit/reactstrap-v8-j1pprd?file=Example.js

I am running react@16.8.6 and also had the issue with reactstrap@8.0.0 (there is no way I could be running an earlier version of react as I'm using hooks quite extensively).

So the simple "fix" is just to change how you do the imports for reactstrap.

@2yk
Copy link

2yk commented Apr 25, 2019

Thanks to @leighmetzroth

I got a fix. I am also using react@16.8.6 with reactstrap@8.0.0 and I was also importing DropdownToggle from reactstrap directly. Adding UncontrolledDropdown as per example given by @leighmetzroth helped me out.

Earlier:

<DropdownToggle nav>
  <img src={avatar} className="img-avatar" alt="admin" />
</DropdownToggle>

Fixed code:

<UncontrolledDropdown>
  <DropdownToggle nav>
    <img src={avatar} className="img-avatar" alt="admin" />
  </DropdownToggle>
</UncontrolledDropdown>

@TheSharpieOne
Copy link
Member

Ok, so when importing directly it seems that two different versions/instances of DropdownContext are being used. To avoid this, always import things the same way (or know which import style is getting used under the hood.)
reactstrap provides a few different flavors to import: es, cjs, UMD, as src (as well as bundled and minified versions of each... because why not) (see here https://unpkg.com/reactstrap@8.0.0/ for the generated files)
Using different import types means that Dropdown from 'reactstrap' can end up getting /es/DropdownContext.js where DropdownToggle from 'reactstrap/lib/DropdownToggle' import references lib/DropdownContext.js These files are different and reference different context instances.

@twheys
Copy link
Author

twheys commented Apr 29, 2019

@TheSharpieOne with react 16.8 I get the same error. @YaroslavLyzlov no I did not solve the issue, but rolling back to reactstrap 7.1 fixed it for me.

@canotech
Copy link

I have the same Issue for me, version 8.0.0 React 16.x.x

@TheSharpieOne
Copy link
Member

@twheys, @canotech: Can you create an example showing the issue via something like stackblitz

@canotech
Copy link

@TheSharpieOne

import { PureComponent } from 'react'
import Link from 'next/link'
import Router from 'next/router'
import { connect } from 'react-redux'
import { FaUserCircle } from 'react-icons/fa'

import {
  NavLink,
  Collapse,
  Navbar,
  NavbarToggler,
  NavbarBrand,
  NavItem,
  Nav,
  UncontrolledDropdown,
  DropdownToggle,
  DropdownMenu,
  DropdownItem,
  Label,
} from 'reactstrap'
import { GoSignOut } from 'react-icons/go'

import { Routes } from '../../constants'
import { doLogOut} from '../../redux/modules/security'
import { logOut  } from '../../services/security'
import { openAlert } from '../../redux/modules/notificationsAlerts'


class NavbarComponent extends PureComponent {
  constructor(props){
    super(props)
    this.state = {
      isOpen: false,
    }
    this.logOutUser = this.logOutUser.bind(this)
    this.toggle = this.toggle.bind(this)
  }
  

  getRoutesWithoutAuthentication(){
    return this.props.url === Routes.assignPassword ||  this.props.url=== Routes.recoveryPassword || Routes.terms || Routes.privacy
  }

  logOutUser(){
    logOut().then((resp)=>{
      if(resp.status === 200){
        this.props.doLogOut()
        this.props.openAlert('success', '¡Adiós, Vuelve Pronto!')
        Router.push({pathname: Routes.home})
      }
    }).catch((e)=>{
      console.log('error',e)
      if(e){
        if(e.response){
          if(e.response.status !== 401)
            this.props.openAlert('error', 'Sucedió un error al cerrar su sesión. Intente de nuevo')
        }
      }
    })
  }
  
  toggle() {
    this.setState({
      isOpen: !this.state.isOpen
    })
  }

  render() {
    let unauthenticated = false
    if(!this.props.authenticated && this.getRoutesWithoutAuthentication()){
      unauthenticated = true
    }

    if(!this.props.authenticated && !unauthenticated) return null

    return (
      <Navbar color="primary" light expand="md" className="box-shadow" >
        <NavbarBrand href="/">
          <Link href={Routes.home}>
            <a>
              <img width="150px" src="/static/images/navbar-logo.png" alt="Dentegra B2B" />
            </a>
          </Link>
        </NavbarBrand>
        <NavbarToggler onClick={this.toggle}/>
        { !unauthenticated ?
          <Collapse isOpen={this.state.isOpen} navbar>
            <Nav className="ml-auto" navbar>
              <NavItem>
                <Link href={Routes.quotations}>
                  <NavLink href={Routes.quotations}>Cotizaciones</NavLink>
                </Link>
              </NavItem>
              <NavItem>
                <Link href={Routes.request}>
                  <NavLink  href={Routes.request}>Solicitudes</NavLink>
                </Link>
              </NavItem>
              <NavItem>
                <Link href={Routes.policies}>
                  <NavLink href={Routes.policies}>Pólizas</NavLink>
                </Link>
              </NavItem>
              <NavItem>
                <Link href={Routes.notifications}>
                  <NavLink href={Routes.notifications}>Notificaciones</NavLink>
                </Link>
              </NavItem>
              <UncontrolledDropdown nav inNavbar>
                <DropdownToggle nav>
                  <FaUserCircle className="icon-size"/>
                </DropdownToggle>
                <DropdownMenu right>
                  <Link href={Routes.home}>
                    <a>
                      <DropdownItem>
                        <Label className="text-dark cursor-pointer"> Home </Label>
                      </DropdownItem>
                    </a>
                  </Link>
                  <Link href={Routes.profile}>
                    <a>
                      <DropdownItem>
                        <Label className="text-dark cursor-pointer"> Mi cuenta</Label>
                      </DropdownItem>
                    </a>
                  </Link>
                  <DropdownItem divider />
                  <DropdownItem onClick={()=>this.logOutUser()}>
                    Salir {' '} <GoSignOut />
                  </DropdownItem>
                </DropdownMenu>
              </UncontrolledDropdown>
            </Nav>
          </Collapse>: null
        }
      </Navbar>
    )
  }
}

export default connect(state => ({
  authenticated: state.security.authenticated,
  username: state.security.username,
}), { doLogOut, openAlert })(NavbarComponent)

@TheSharpieOne
Copy link
Member

@canotech the dropdown in your example works perfectly: https://stackblitz.com/edit/reactstrap-v8-n8zlcz?file=Example.js

Make sure the version of react you are using is 16.6+

@twheys
Copy link
Author

twheys commented Apr 30, 2019

https://stackblitz.com/edit/react-5evsqd

To reproduce the error, click on the dropdown button

@canotech
Copy link

@TheSharpieOne and also I make sure the version of react-dom is 16.8.+

That's works for me! thank you @TheSharpieOne !

@unski11ed
Copy link

Please expose the context as said in #1462 . There is no way to import it via /es/DropdownContext nor /lib/DropdownContext nor /src/DropdownContext in NextJs.

Every possibility returns the same error upon compilation Unexpected Identifier: (function (exports, require, module, __filename, __dirname) { import React from 'react';.

On standard Webpack + Babel configuration it works fine but still looks hacky.

@hammooooody
Copy link

This simply solved it for me. I added toggle prop with an empty function.

<Dropdown
        isOpen={isOpen}
        toggle={() => {}}
      >

may also work with UncontrolledDropdown haven't tried it tho.

@paulzmuda
Copy link

paulzmuda commented Sep 10, 2019

@canotech the dropdown in your example works perfectly: https://stackblitz.com/edit/reactstrap-v8-n8zlcz?file=Example.js

Make sure the version of react you are using is 16.6+

I didn't even have to use UncontrolledDropdown to replace Dropdown. From the quoted example I found missing property "inNavbar" and added to Dropdown as below:

<Dropdown nav inNavbar isOpen={this.state.menuOpen} toggle={this.toggleMenu}>

The one property.

Using React 16.8.6 and Reactstrap 8.0.1

@onlywicked
Copy link

Anyone working on it. I would like to take this issue.

@TheSharpieOne
Copy link
Member

@onlywicked, It's all your. Thank you!

@TheSharpieOne
Copy link
Member

stackblitz.com/edit/react-5evsqd

To reproduce the error, click on the dropdown button

Dropdown requires onToggle, it is not provided in your example. If you used UncontrolledDropdown or provide onToggle with the minimum version of react mentioned above (16.6) it works fine.

@thuandv1
Copy link

it still not works in v8.9.0

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

Successfully merging a pull request may close this issue.