user2441535
user2441535

Reputation:

history.pushState not working in Chrome on iOS when executing without an interaction

It seems like history.pushState is not working in Chrome on iOS when executed manually without any touch/click interaction.

I need help with understanding why iOS Chrome does this, and if possible, how to fix it.

https://codepen.io/grymer/pen/OOmebv

Here is a codepen with a minimum working example. To test it, you need to fork the pen and go into debug view in Chrome on an iOS device.

Then you will see "a button that says "To B". Press it and then use browser back. You will see that this behavior differs from any other browser.

var React, { Component } = React;
var { BrowserRouter, Redirect, Route, Switch } = ReactRouterDOM;

class App extends Component {
  render() {
    return (
      <BrowserRouter basename={location.href}>
        <Switch>
          <Route path="/b" component={B} />
          <Route component={A} />
        </Switch>
      </BrowserRouter>
    );
  }
}

class A extends Component {
  constructor() {
    super();

    this.state = {};

    this.handleClick = this.handleClick.bind(this);
  }

  render() {
    if(this.state.redirect) {
      return <Redirect push to="/b" />
    }

    return (
      <div>
        On page A
        <button onClick={this.handleClick}>To B</button>
      </div>
    );
  }

  handleClick() {
    this.setState({ redirect: true });
  }
}

class B extends Component {
  constructor() {
    super();

    this.state = {
      showModal: false
    };

    this.handleClick = this.handleClick.bind(this);
  }

  componentDidMount() {
    this.button.click(); // comment this line to manually open the modal by tapping the button
  }

  render() {
    return (
      <div>
        On page B
        { this.state.showModal ? <Modal history={this.props.history} onClose={() => this.setState({ showModal: false }) } /> : null }
        <button ref={(el) => this.button = el } onClick={this.handleClick}>Open modal</button>
      </div>
    );
  }

  handleClick() {
    this.setState({
      showModal: true
    });
  }
}

class Modal extends Component {
  constructor() {
    super();

    this.handleClick = this.handleClick.bind(this);
    this.onPopState = this.onPopState.bind(this);
  }

  componentDidMount() {
    this.props.history.push(this.props.history.location.pathname, { type: 'modal' });
    window.addEventListener('popstate', this.onPopState);
  }

  componentWillUnmount() {
    window.removeEventListener('popstate', this.onPopState);
  }

  render() {
    return (
      <div>
        Modal is opened
        <button onClick={this.handleClick}>Close modal</button>
      </div>
    );
  }

  handleClick() {
    this.props.onClose();
    this.props.history.goBack();
  }

  onPopState() {
    this.props.onClose();
  }
}

ReactDOM.render(<App />, document.getElementById('react-container'));

Upvotes: 1

Views: 2596

Answers (1)

user2441535
user2441535

Reputation:

Chromium team has acknowledged and they are working on a fix.

https://bugs.chromium.org/p/chromium/issues/detail?id=783382#c3

Upvotes: 2

Related Questions