Ahmad Al-kheat Ahmad Al-kheat - 2 months ago 15
React JSX Question

ref callback is being applied to first matching class

I have a simple component that has a render like this:

render: function(){
return (
<textarea className="wmd-input" id="wmd-input" ref={this.initiatePagedown}></textarea>
)
}

initiatePagedown: function(input){
//code that initiates markdown editor.
attr = $(input).attr('id').split('wmd-input')[1];
converter = new Markdown.Converter();
Markdown.Extra.init(converter, {highlighter: "highlight"});
editor = new Markdown.Editor(converter, attr);
return editor.run();
},


The component mounts n different times, hence creating multiple textareas.

The problem is the ref callback is running with the input of the first component, so it's always the first component that's manipulated, not the one that I select. So let's say this component was mounted twice, then the ref callback will be called on the first component instance twice, not once of each component instance. How do I solve this issue?

Answer

You're using the Editor to point to an id on the page because you're passing in the second argument, attr:

new Markdown.Editor(converter, attr); 

Check out the documentation for the second argument of the constructor:

If given, this argument is a string, appended to the HTML element ids of the three elements used by the editor...so you may create the second input box as <textarea id="wmd-input-2"> and pass the string "-2" as the second argument to the constructor.

Right now you're always creating an editor with the same id:

id="wmd-input"

So the editor constructor will always match every existing instance of that id on the page.

This is a very poor API forcing you to point to element IDs. As a workaround I would probably make the id a prop you pass in, so that the wrapping component/page can decide how many editors should be there, and you can build the id like this

return (
    <textarea id={ `wmd-input-${ this.props.id }` } />
)

Then you can instantiate the unfortunate API with something like

editor = new Markdown.Editor(converter, `-${ this.props.id }`);
Comments