简体   繁体   中英

React-Router Link, how to trigger a click event on a Link from another component

I'm trying to set up a series of React-Router to have navigation within a certain component. I have it set up so the link tags work correctly but I'm trying to style them to look like this:

在此处输入图片说明

The styling is set up like this:

  <div className="btn-group" data-toggle="buttons">
      <label className="btn btn-primary-outline active">
        <input type="radio" name="options" id="option1" autocomplete="off" checked />Payments
      </label>
      <label className="btn btn-primary-outline">
        <input type="radio" name="options" id="option2" autocomplete="off" /> Bills
      </label>
      <label className="btn btn-primary-outline">
        <input type="radio" name="options" id="option3" autocomplete="off" /> Charge
      </label>
    </div>

And the current series of Links looks like this (with no styling):

<ul>
  <Link to='/options/option1'>option1</Link>
  <Link to='/options/option2'>option2</Link>
  <Link to='/options/option3'>option3</Link>
</ul>

The HTML (top) is written in HTML, not JSX, but that's not the issue. I am trying to combine the Link Components into the HTML above so that the options will trigger the functionality of the link tags.

In the React documentation I found this:

For communication between two components that don't have a parent-child relationship, you can set up your own global event system. Subscribe to events in componentDidMount(), unsubscribe in componentWillUnmount(), and call setState() when you receive an event. Flux pattern is one of the possible ways to arrange this.

So this gave me the idea of putting the Link tags inside of their respective labels, giving them a style of {{display: 'none'}}, and having the clicks on the radio buttons trigger a click on the respective Link tag. That would ensure all the same functionality happens that we'd expect from the Link tag (pushing to browser history etc).

However, the following is not working:

<label className="btn btn-primary-outline active" onClick={() => document.getElementById('linkToOption1').click() }>
    <Link to='/options/option1' id="linkToOption1" style={{display: 'none'}}>Option1</Link>
        <input type="radio" name="options" id="option1" autoComplete="off" defaultChecked />Option1
    </label>

In the previous example you can see I created an onClick event handler that selects the id of the Link tag and triggers a click.

I was able to solve my problem so I am posting what worked for me. Please answer or comment if there's changes or a better solution.

I wasn't able to trigger a click event on a Link, but I was able to simulate the aspects that I needed.

For this to work I needed the following:

  1. on a click event push to browserHistory to update the route
  2. link the 'active' css class to the current view/URL (I accomplished this through component state)
  3. update the state whenever the url is changed (modified state on window popstate event, and also update the currentView state on component will mount)

This results in the ability for the correct tab to be highlighted when a tab is clicked, when the url is manually changed to a certain route, and when the browsers back / forward buttons are used.

This is all the code in my navmenu file that creates a pretty cool navigation component and works with react-router and browserHistory.

import React, { Component, PropTypes } from 'react'
import { Link, browserHistory } from 'react-router'

class Navmenu extends Component {
  constructor(props) {
    super(props)
    this.state = { currentView: '' }
    this.getClasses.bind(this)
  }

  // in case of url being manually set, figure out correct tab to highlight
  // add event listener to update the state whenever the back/forward buttons are used.
  componentWillMount() {
    this.changeLocation()
    window.addEventListener('popstate', this.changeLocation.bind(this))
  }

  componentWillUnmount() {
    window.removeEventListener('popstate', this.changeLocation.bind(this))
  }

  // update state based on the URL
  changeLocation() {
    const path = window.location.pathname.split('/')
    const currentView = path[path.length - 1]
    this.setState({ currentView })
  }

  // update state and update react-router route
  navigateToRoute(route) {
    this.setState({ currentView: route })
    browserHistory.push(`/options/${route}`)
  }

  // give correct tab the 'active' bootstrap class
  getClasses(link) {
    let classes = 'btn btn-primary-outline flex-button'
    if (this.state.currentView === link) {
      classes += ' active'
    }
    return classes
  }

  render() {
    return (
      <div className="btn-group flex-navbar" data-toggle="buttons">
        <label className={this.getClasses('option1')} onClick={() => this.navigateToRoute('option1')}>
          <input type="radio" name="options" id="option1" autoComplete="off" defaultChecked />option1
        </label>
        <label className={this.getClasses('option2')} onClick={() => this.navigateToRoute('option2')}>
          <input type="radio" name="options" id="option2" autoComplete="off" /> option2
        </label>
        <label className={this.getClasses('option3')} onClick={() => this.navigateToRoute('option3')}>
          <input type="radio" name="options" id="option2" autoComplete="off" /> option3
        </label>
      </div>
    )
  }
}

export default Navmenu

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM