gilbarbara / react-floater

Advanced tooltips for React
https://codesandbox.io/s/github/gilbarbara/react-floater/tree/main/demo
MIT License
220 stars 37 forks source link

ReactFloater erros on tour stop #46

Closed sarates closed 5 years ago

sarates commented 6 years ago

Expected behavior

Tour stops, I make some operations, tour run

Actual behavior

Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the ReactFloater component.

Steps to reproduce the problem

if ([EVENTS.STEP_BEFORE].includes(type) && !this.checkVisible(htmlTarget)) {
  this.setState({
    run : false,
    tutorialLoading: true
  }, () => {
    this.setState({
      run : true,
      stepIndex : 8
    });
  });
}

React version

"react": "^15.5.4",

React-Joyride version

"react-joyride": "^2.0.0-10",

Error stack

If you are having UI issues, make sure to send a public URL or codesandbox example.

varzock commented 6 years ago

Struggling with exact the same errors with React version 15.4.1

Izhaki commented 6 years ago

Same issue here.

    "react": "16.3.1",
    "react-dom": "16.3.1",
    "react-joyride": "2.0.0-11",

This may give further insights:

image

gilbarbara commented 6 years ago

@sarates Where are you using the code in the "Steps to reproduce the problem"?

Izhaki commented 6 years ago

@gilbarbara In our case:

let tourCount = 0;

interface ITourProps {
  steps:any[];
  locale:object;
}

class Tour extends React.Component<ITourProps> {
  state = {
    run: false
  };

  componentDidMount() {
    this.setState({ run: true });
  }

  callback = (tour) => {
    const { action, type } = tour;
    if (action === ACTIONS.CLOSE && type === EVENTS.STEP_AFTER) {
      this.setState({run: false});
    }
  };

  render() {
    const { run } = this.state;
    const { steps, locale } = this.props;
    return (
      <Joyride
        key={tourCount++}
        steps={steps}
        locale={locale}
        run={run}
        callback={this.callback}
        continuous={true}
        showSkipButton={true}
      />
    );
  }
}

We want close to exit the tour.

gilbarbara commented 6 years ago

Is this is still happening in react-joyride@2.0.0-12

gitowiec commented 5 years ago

@gilbarbara I have the same error with following setup (just wanted to report as issue but used new github feature) :

Expected behavior

Closes clean without thrown errors.

Actual behavior

React-Joyride when closed with X in floater (step) throws:

react-dom.development.js:512 Warning: Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
    in ReactFloater (created by JoyrideStep)
    in div (created by JoyrideStep)
    in JoyrideStep (created by Joyride)
    in div (created by Joyride)
    in Joyride (created by JoyrideFacade)
    in JoyrideFacade (created by WalkthroughRunner)

Steps to reproduce the problem

Just run Joyride with this fascade and composition

export class JoyrideFacade extends React.Component<JoyrideFacadeOuterProps> {

  joyRideCallback = (state: State) => {
    switch (state.action) {
      case 'close':
      case 'skip':
        this.props.handleStop();
        break;
      case 'next':
        if (state.index === state.size - 1 && state.status === 'finished') {
          this.props.handleStop();
        }
    }
  };

  render() {
    return (<Joyride
      run={this.props.run}
      callback={this.joyRideCallback}
      steps={this.props.steps}
      {...joyrideDefaultProps}
    />);
  }

}

export class WalkthroughRunner extends React.Component<WalkthroughRunnerOuterProps> {

  private storage: LocalStorageProxy;

  private static storagePlaceholder = 'autorun';

  constructor(props, context: any) {
    super(props, context);
    this.storage = new LocalStorageProxy('walkthroughs', this.props.walkthroughName);
  }

  shouldRenderChildren(): boolean {
    if (this.props.walkthroughState.isRunning && this.props.walkthroughState.name === this.props.walkthroughName) {
      return true;
    }
    if (false === this.storage.getItem<boolean>(WalkthroughRunner.storagePlaceholder)) {
      return false;
    }
    return true;
  }

  handleStop = () => {
    this.storage.setItem(WalkthroughRunner.storagePlaceholder, false);
    this.props.walkthroughActions.stopWalkthrough();
  };

  render() {
    console.log(this.props);
    const show = this.shouldRenderChildren();
    console.log(show);
    if (show) {
      return this.props.children(this.handleStop, true);
    }
    return null;
  }

}
                <WalkthroughDataProvider
                  render={({ walkthroughState }, walkthroughActions) => (
                    <WalkthroughRunner
                      walkthroughName={WalkthroughName.DASHBOARD}
                      walkthroughState={walkthroughState}
                      walkthroughActions={walkthroughActions}
                    >
                      {(handleStop, run) => (
                        <JoyrideFacade
                          run={run}
                          steps={steps}
                          handleStop={handleStop}
                        />
                      )}
                    </WalkthroughRunner>
                  )}
                />

React version

16.4

React-Joyride version

@next

Browser name and version

Chromium Version 70.0.3538.77 (Official Build) Built on Ubuntu , running on Ubuntu 18.04 (64-bit)

Error stack (if available)

react-dom.development.js:512 Warning: Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
    in ReactFloater (created by JoyrideStep)
    in div (created by JoyrideStep)
    in JoyrideStep (created by Joyride)
    in div (created by Joyride)
    in Joyride (created by JoyrideFacade)
    in JoyrideFacade (created by WalkthroughRunner)
gitowiec commented 5 years ago

Guys do you have any clues? I'm trying to fix this issue. I am running Chrome debugger with "Pause on caught exceptions" but its a little hard to follow what's going on in the code.

gitowiec commented 5 years ago

@gilbarbara

Is this is still happening in react-joyride@2.0.0-12

I am using "version": "2.0.0-15",

gitowiec commented 5 years ago

It seems to me that the error is due to the fact that one of the components in the react-joyride <-> react-floater tree when pressing the close icon removes the react-floater (or popper.js) and creates a new step. Then it wants to run it, but there is no more react-floater to handle it so the error shows up.

gilbarbara commented 5 years ago

This will be handled in #45