1

I have a react code, where I have " < a > " component. When I click on "< a >", I want to change it's href field. For that, I have "ref" to get the component inside the "onclick" method like this:

class SomeComponent {
    public ref: React.RefObject<any>;

    constructor(props: any) {
        super(props);
        this.ref = React.createRef();
    }

    render() {
        <a
          href="#"
          ref={ this.ref }
          onClick={this.clicked()}
        />
    } 

    private clicked() {
        const link = this.ref.current;
        link.href = "some_link"; // This doesn't have any effect on the "a" element
    }
}

But as a result "href" doesn't get updated. It stays to be "#" after the click as well. Any idea how can I make it work?

1 Answers1

2

There are a lot of typos or bugs in the code that you've posted:

  • Missing extends React.Component.
  • Missing return in render().
  • Calling this.clicked() instead of passing a function to onClick.
  • Not checking that link isn't null before assigning to it.
  • Not calling e.preventDefault() on the click event to prevent rerendering to "#".

You could fix all of those errors and it would mostly work, but if the component re-renders for any reason then the the href will go back to "#" because that is what's set in the render().

class SomeComponent extends React.Component {
  public ref: React.RefObject<HTMLAnchorElement>;

  constructor(props: {}) {
    super(props);
    this.ref = React.createRef();
  }

  render() {
    return (
      <a href="#" ref={this.ref} onClick={this.clicked}>
        Anchor Text
      </a>
    );
  }

  private clicked = (e: React.MouseEvent) => {
    const link = this.ref.current;
    if (link && link.href === "#" ) {
      e.preventDefault();
      link.href = "some_link";
    }
  };
}

Just Use State

It doesn't make any sense to modify the href through DOM manipulation when you are the one who is setting the href in the first place. Store the current value of the href in this.state and render your link with href={this.state.href}.

We still need to conditionally call e.preventDefault() only when href is "#" so this is still a weird design that can be improved. Maybe show a div until its clicked an an a after? But per your requirements, this will work:

class SomeComponent extends React.Component<{}, { href: string }> {
  constructor(props: {}) {
    super(props);
    this.state = {
      href: "#"
    };
  }

  render() {
    return (
      <a href={this.state.href} onClick={this.clicked}>
        Anchor Text
      </a>
    );
  }

  private clicked = (e: React.MouseEvent) => {
    if ( this.state.href === "#" ) {
      e.preventDefault();
      this.setState({ href: "some_link" });
    }
  };
}
Linda Paiste
  • 38,446
  • 6
  • 64
  • 102