Liondancer Liondancer - 2 months ago 18
React JSX Question

Setting state with methods passed into dumb components

Within my smart component, I have methods that I want to use to set state of my smart component. When a user interacts with the dumb component, the methods passed down from the smart component will be triggered and that to change the state of my smart component

In my code below, I want my

setHighlight
to change my
state.highlight
to a string
onClick
.
clearHighlight
has the same functionality except it sets
this.state.highlight = null
. Once this state has been set,
this.state.highlight
is passed to my
PrettyPrintPageSource
in order to perform the logic in
highlightTag
.

My code is currently showing these errors:

warning.js:44Warning: 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 HomePage component.warning @ warning.js:44

warning.js:44Warning: Failed prop type: Required prop `setHighlightTag` was not specified in `TagSummary`.
in TagSummary (created by HomePage)
in HomePage (created by Connect(HomePage))
in Connect(HomePage) (created by RouterContext)
in div (created by App)
in MuiThemeProvider (created by App)
in App (created by RouterContext)
in RouterContext (created by Router)
in Router
in Providerwarning @ warning.js:44
warning.js:44Warning: Failed prop type: Required prop `clearHighlight` was not specified in `TagSummary`.
in TagSummary (created by HomePage)
in HomePage (created by Connect(HomePage))
in Connect(HomePage) (created by RouterContext)
in div (created by App)
in MuiThemeProvider (created by App)
in App (created by RouterContext)
in RouterContext (created by Router)
in Router
in Provider


Here is my code:

class HomePage extends React.Component {
constructor(props) {
super(props);
this.state = {
highlight: null
};
this.getPageSource = this.getPageSource.bind(this);
this.updateURLstate = this.updateURLstate.bind(this);
this.highlightTag = this.highlightTag.bind(this);
this.clearHighlight = this.clearHighlight(this);
this.setHighlightTag = this.setHighlightTag(this);
}

getPageSource(event) {
event.preventDefault();
this.props.actions.getPageSource(this.state.url);
}

updateURLstate(event) {
const url = event.target.value;
this.setState({
url
});
}

setHighlightTag(tag) {
this.setState({
highlight: tag
});
}

highlightTag(pageSource, tag) {
if (tag) {
let re = new RegExp(tag, "g");
pageSource.replace(re, "<span class='red'>"+ tag +"</span>")
}
}

clearHighlight() {
this.setState({
highlight: null
});
}

render() {
return (
<div>
<UrlForm
onSearch={ this.getPageSource }
onChange={ this.updateURLstate }
/>

<PrettyPrintPageSource
badUrl={ this.props.payload.error }
prettyPrintPageSource={ this.props.payload.prettySource }
highlighter={ this.highlightTag }
tag={ this.state.highlight }
/>
<TagSummary
tags={ this.props.payload.tagData }
setHighlightTag={ this.setHighlightTag }
clearHighlight={ this.clearHighlight }
/>
</div>
);
}
}


TagSummary dumb Component:

const TagSummary = ({ tags, setHighlightTag, clearHighlight }) => {
if (!tags) {
return <div />;
}
return (
<div>
{Object.keys(tags).map((tag) => {
return (
<div key={ tag }>
<button type="button" onClick={ setHighlightTag.bind(this, tag) }>
<pre>&lt;{ tag }&gt;</pre>
</button>
<p>{ tags[tag] }</p>
</div>

);
})}
<button onClick={ clearHighlight }>Clear</button>
</div>
);
};


PrettyPrintPageSource dumb Component:

const PrettyPrintPageSource = ({ prettyPrintPageSource, badUrl, highlighter, tag }) => {
if (badUrl) {
return (
<div>
Bad URL!
</div>
);
} else {

let processedPageSource = highlighter.bind(this, prettyPrintPageSource, tag);

return (
<pre>
{ processedPageSource }
</pre>
);
}
};

Answer

You forgot bind clearHighlight and setHighlightTag methods. Change those lines :

  constructor(){
   ....
   this.clearHighlight = this.clearHighlight.bind(this);
   this.setHighlightTag = this.setHighlightTag.bind(this);
   }