ReactJS - Conditional rendering not working - javascript

Basically, the code snippet below is for the Close/Edit icon: Once clicked in "Close" mode, it will change to the "Edit" icon and pass the rowId and a "1" parameter in the handleEdit function; and, once in "Edit" mode, it will pass the rowId and a "0" parameter.
The problem is that it only goes to the condition of editClose === 1, although it updates the editDeleteTag to 1; it never seems to render the stylesEditOptions icon along with it's condition.
I'm new to React, so I might be missing something here.
childComponenent.jsx
funcEdit = (editClose) => {
if (editClose === 0) {
return (<div className={styles.editOptions}>
<Input type="button" className={styles.closeIcon} onClick={() => this.props.handleEdit(rowIndex, 1)} />
</div >)
} else {
return (<div className={styles.editOptions}>
<Input type="button" className={styles.EditIcon} onClick={() => this.props.handleEdit(rowIndex, 0)} />
</div >)
}
}
render()
let locArr = [...this.state.mainArray];
For looop .... {
if (locArr[i].editOrDeleteTag === 0) {
locArr[i].editOrDelete = this.funcEdit(1);
} else {
locArr[i].editOrDelete = this.funcEdit(0);
}
}
return(
...
<BootstrapTable data={locArr}
...
)
parentComponent.jsx
handleEdit = (rowId, toggle) => {
let locArr = [...this.state.mainArray];
locArr[rowId.rowIndex].editOrDeleteTag = toggle
this.setState({ mainArray : locArr });
};

The most likely reason is the fact that you are mutating the state.
When making state changes to a nested object you need to update all parent elements.
So in your handleEdit try to use
locArr[rowId.rowIndex] = {
...locArr[rowId.rowIndex],
editOrDeleteTag: toggle
};
instead of
locArr[rowId.rowIndex].editOrDeleuteTag = toggle;

Related

Changing style of another element using react

I'm relatively new to react and am totally lost trying to figure out how to make an Component appear when I press on a button. I've set up the code as such
<Button>GO</Button>
<CalendarIcon id="calendar visibility="hidden"/>
and then useVisibility()
export default function useVisibility() {
const[visibility, setVisibility] = useState("hidden")
useEffect(() => {
function handleVis(){
setVisibility("visible")
}
button.addEventListener("onClick", handleVis)
return () => button.removeEventListener("onClick", handleVis)
}, [])
return visibility
}
My problem is that I don't know how to pass the button into the function so that I can add the event listener. If I am doing this in a totally roundabout way or overcomplicating it please tell me because I am so lost.
Thanks!
What I would do is let each instance where you render a button specify how its click handler should behave as there can be many use cases for a button in a website.
function MyComponent() {
const[isVisible, setIsVisible] = useState(false)
const handleVisibilityToggle = useCallback(
() => setIsVisible(!isVisible),
[isVisible, setIsVisible]
)
...
const visibility = isVisible ? 'unset' : 'hidden'
return (
<>
...
<Button onClick={handleVisibilityToggle}>GO</Button>
<CalendarIcon id="calendar" visibility={visibility}/>
</>
)
}
if you would like to clean up how that code is used and abstract the logic to a visibility hook it would look something like this
function useVisibilityToggle(defaultValue = false) {
const[isVisible, setIsVisible] = useState(defaultValue)
const toggleVisibility = useCallback(
() => setIsVisible(!isVisible),
[isVisible, setIsVisible]
)
const visibility = isVisible ? 'visible' : 'hidden'
return [visibility, toggleVisibility]
}
function MyComponent() {
const [visibility, toggleVisibility] = useVisibilityToggle(false)
return (
<>
...
<Button onClick={toggleVisibility}>GO</Button>
<CalendarIcon id="calendar" visibility={visibility}/>
</>
)
}
Check the first example here: https://reactjs.org/docs/hooks-state.html
function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
That should show you how to manipulate the state when the button is clicked. Next you wanted to show/hide something when that button is clicked.
First let's change that useState to a boolean one, so
const [hidden, setHidden] = useState(false);
Then we can change the button so that it uses the previous state to set the new one. You should never use the hidden in the setHidden, but instead pass a function into it, which gets the previous value as parameter.
<button onClick={() => setHidden(prevHidden => !prevHidden)}>
And now we want to use that value, so we can add something below the button:
{ !hidden ? (<p>This text is visible</p>) : (<></>) }
Working example: https://codesandbox.io/s/strange-williamson-wuhnb?file=/src/App.js
Your code looks like you are trying to build a custom hook, that's more advanced stuff, and if you are super new to React, you won't need that right now.
Your main goal is to show CalendarIcon component visible when you click on GO Button.
So you need a state lets say visible variable to control this.
You can update this state onClick of your Button as shown below to true or false, And make visibility="visible" always.
When visible will be true your CalendarIcon will appear.
const [visible, toggleVisibility] = useState(false)
<Button onClick={()=> toggleVisibility(!visible)}>GO</Button>
{visible && <CalendarIcon id="calendar" visibility="visible"/>}

Generate React/NextJS dynamic components and bind events from static HTML [duplicate]

I have a string , i.e,
let string= "Hello <b>Click here</b>";
render() {
return (<div dangerouslySetInnerHTML={this.createMarkup(value)}/>
}
createMarkup = value => {
return { __html: value };
};
What I would like is to be able to add an onclick event to the <b> tag perform state manipulations on click.
The underlying problem is where I had a function which was supposed to render whatever is passed by the API. The API would send a string 'Money received for order ID 123', or could be any string that I have no control over. Later, I got a requirement where the item that is bolded must be clickable, so as to perform some actions. I didn't have any other way to solve it.
How can I achieve this?
Caveat: This sounds like an X/Y problem, where the underlying problem (whatever it is) should be solved differently, so that you don't have to add a click handler to a DOM element created via dangerouslySetInnerHTML (ideally, so you don't have to create DOM elements via dangerouslySetInnerHTML at all). But answering the question you asked: (You've clarified the use case; solution #1 below applies and isn't poor practice.)
I don't think you can do that directly. Two solutions I can think of:
Use delegated event handler on the div: Add a click handler on the div, but then only take action if the click passed through the b element.
Use a ref on the div, and then hook the click handler up in componentDidMount and componentDidUpdate (finding the b element within the div via querySelector or similar), something along these lines:
Here's an example of #1:
<div onClick={this.clickHandler} dangerouslySetInnerHTML={this.createMarkup(string)}/>
...where clickHandler is
clickHandler(e) {
// `target` is the element the click was on (the div we hooked or an element
// with in it), `currentTarget` is the div we hooked the event on
const el = e.target.closest("B");
if (el && e.currentTarget.contains(el)) {
// ...do your state change...
}
}
...or if you need to support older browsers without ParentNode#closest:
clickHandler(e) {
// `target` is the element the click was on (the div we hooked or an element
// with in it), `currentTarget` is the div we hooked the event on
let el = e.target;
while (el && el !== e.currentTarget && el.tagName !== "B") {
el = el.parentNode;
}
if (el && el.tagName === "B") {
// ...do your state change...
}
}
...and where you bind clickHandler in the constructor (rather than using a property with an arrow function; why: 1, 2):
this.clickHandler = this.clickHandler.bind(this);
Live Example:
let string = "Hello <b>Click here</b>";
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
clicks: 0
};
this.clickHandler = this.clickHandler.bind(this);
}
clickHandler(e) {
// `target` is the element the click was on (the div we hooked or an element
// with in it), `currentTarget` is the div we hooked the event on
// Version supporting older browsers:
let el = e.target;
while (el && el !== e.currentTarget && el.tagName !== "B") {
el = el.parentNode;
}
if (el && el.tagName === "B") {
this.setState(({clicks}) => ({clicks: clicks + 1}));
}
// Alternative for modern browsers:
/*
const el = e.target.closest("B");
if (el && e.currentTarget.contains(el)) {
this.setState(({clicks}) => ({clicks: clicks + 1}));
}
*/
}
createMarkup = value => {
return { __html: value };
};
render() {
const {clicks} = this.state;
return [
<div>Clicks: {clicks}</div>,
<div onClick={this.clickHandler} dangerouslySetInnerHTML={this.createMarkup(string)}/>
];
}
}
ReactDOM.render(
<Example />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Here's an example of #2, but don't do this if A) You can solve the underlying problem separately, or B) #1 works:
let string = "Hello <b>Click here</b>";
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
clicks: 0
};
this.divRef = React.createRef();
this.hooked = null;
this.clickHandler = this.clickHandler.bind(this);
}
clickHandler() {
this.setState(({clicks}) => ({clicks: clicks + 1}));
}
hookDivContents() {
// Get the b element
const b = this.divRef.current && this.divRef.current.querySelector("b");
// No-op if it's not there or it's the same element we have hooked
if (!b || b === this.hooked) {
return;
}
// Unhook the old, hook the new
if (this.hooked) {
this.hooked.removeEventListener("click", this.clickHandler);
}
this.hooked = this.divRef.current;
this.hooked.addEventListener("click", this.clickHandler);
}
componentDidMount() {
this.hookDivContents();
}
componentDidUpdate() {
this.hookDivContents();
}
createMarkup = value => {
return { __html: value };
};
render() {
const {clicks} = this.state;
return [
<div>Clicks: {clicks}</div>,
<div ref={this.divRef} dangerouslySetInnerHTML={this.createMarkup(string)}/>
];
}
}
ReactDOM.render(
<Example />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Refs are an "escape hatch" giving you direct DOM access. Don't use refs lightly; usually, there's a better choice.
But again: I would solve the underlying problem, whatever it is, differently.
react-html-parser can convert HTML strings into React components.
using transform callback function you can update any tag in HTML string with JSX tag adding any properties and event listeners.
This is how I used it:
ReactHtmlParser(item.value, {
transform: (node) => {
if (node.name === 'a' && node.attribs && node.attribs.href) {
const matched = node.attribs.href.match(/^activity\/([0-9]+)$/i);
if (matched && matched[1]) { // activity id
return <a
href={node.attribs.href}
onClick={(e) => {
e.preventDefault();
this.props.openActivityModal(matched[1]);
}}
>{node.children[0].data}</a>
}
}
}
})
Here is a clean way to achieve your needs. By splitting your string depending on the <br> tag you can end up with an mappable array of text :
class BoldText extends React.Component {
constructor(props) {
super(props)
this.state = {
input: "Money received for order ID <b>123</b>, wow for real, so <b>cool</b> its insane"
}
}
boldClick = ev => {
console.log('clicked !')
}
render() {
const { input } = this.state
const a = input.split('</b>')
const filter = /<b>.*<\/b>/
const text = input.split(filter)
const clickable = filter.exec(input)
//<b onClick={this.boldClick}></b>
return (
<div>
<p>{a.map(t => {
const [text, bold] = t.split('<b>')
return <span>{text}<b onClick={this.boldClick}>{bold}</b></span>
})}
</p>
</div>
)
}
}
ReactDOM.render(<BoldText />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.production.min.js"></script>
<idv id='root'>
This solution should solve the problem you mentioned in the comments of the answer above. You can put your API call in the componentDidMount lifecycle function and change your state from there.
You can make the parent tag a <form> and set the onClick="SomeFunction()".
From the child tag that has the HTML string, set type="button".
let string= "Hello <b type='button'>Click here</b>";
render() {
return (
<form onClick={SomeFunction} dangerouslySetInnerHTML =
{this.createMarkup(value)}/>
}
createMarkup = value => {
return { __html: value };
};

getElementById after conditionally rendering with setState

I have a trigger button that will open a dialog asking if a user would like to enable text to speech. Once the dialog is open, I want to focus on the yes button within the dialog by getting the button element by its ID.
When the trigger is pressed, the following function is called:
private openTTSDialog = () => {
if (this.state.ttsDialog === true) {
this.setState({ ttsDialog: false })
} else {
this.setState({ ttsDialog: true }, () => {
// search document once setState is finished
const yesButton = document.getElementById('tts-dialog-yes-button')
log('yesButton', yesButton)
if (yesButton) {
yesButton.focus()
}
})
}
}
And my dialog is conditionally rendered with a ternary expression like this:
{
this.state.ttsDialog ? (
<div className="tts-dialog-container">
<div className="tts-dialog-text-container">
{session.ttsEnabled ? (
<div>
{
strings.disableTTS
}
</div>
) : (
<div>
{
strings.enableTTS
}
</div>
)}
</div>
<div className="tts-dialog-button-container">
<button
aria-label={strings.yes}
tabIndex={0}
className="tts-dialog-button"
id="tts-dialog-yes-button" // this is the button I want to focus
onClick={this.toggleTTS}
>
{
strings.yes
}
</button>
<button
aria-label={strings.no}
tabIndex={0}
className="tts-dialog-cancelButton"
onClick={this.closeTTSDialog}
>
{
strings.no
}
</button>
</div>
</div>
) : null
}
My log for yesButton is undefined. I thought adding the callback function to setState would fix this because I would be searching the document after setState was finished, but I'm still missing something. Any idea what it is?
In the constructor of your class, you should add a ref to your button:
this.myRef = React.createRef();
Then in your button :
<button
ref={this.myRef}
aria-label={strings.yes}
tabIndex={0}
className="tts-dialog-button"
id="tts-dialog-yes-button" // this is the button I want to focus
onClick={this.toggleTTS}
>
Finally, instead of doing:
const yesButton = document.getElementById('tts-dialog-yes-button')
You should do :
const yesButton = = this.myRef.current;
Actually I would also think this should work since you use a callback on setState, so the new render should have completed and the element should already be mounted and accessible. Anyway I think the idiomatic React way for this would be to use a ref (https://reactjs.org/docs/refs-and-the-dom.html) and put it on the button like <button ref={this.yesButton} ...>...</button> and then call this.yesButton.focus(). Have you tried that already?

React - Uncaught ReferenceError: add is not defined

So I'm pretty new to React (and JS) in general. Normally code with Java or C# and I'm not used to the syntax just yet. I did manage to make a simple calculator with React and wanna add the functionality but whenever I try, I get an error that says that my method is not defined.
Basically the function is used to get the prop from my Button component and append it into the Screen component value.
class Button extends React.Component {
constructor(props) {
super(props)
}
add(button) {
let value = button.value
let text = document.getElementByID('screenInput').value
if (value == '=') {
document.getElementById('screenInput').innerHTML = eval(text).toString();
} else if (value == 'C') {
document.getElementById('screenInput').innerHTML = '0':
} else if (value == '+/-' && text != '0') {
document.getElementById('screenInput').innerHTML = `` - (${ text })``;
} else if (value == '\d' || (text.slice(-1) != value && text != '0')) {
document.getElementById('screenInput').innerHTML = text.append(value);
}
}
render() {
return (
<button type='button' value={this.props.value} onClick={() => add(this)}> {this.props.value}</button >
)
}
}
https://jsfiddle.net/q7yakt1v/22/`
So the reason you can't just refer to add like that is it intrinsically bound to the instance of your class Button. So if you want to call it, you'd have to do this.add(this).
The problem you will run into next is that the this you are passing to add isn't the button element, but a reference to the class instance.
I guess I should also add that you don't want to be modifying the DOM directly outside of React like that because React internally keeps track of changes. You should prefer using state/context to apply changes to things outside the immediate scope your component.
As pointed out in a couple of the other answers, the key issue with your code is onClick={() => add(this)}. But I think this is because of a misunderstanding of how state is handled in React.
I have lifted the state of the value of screen into the <Calculator /> component. This way we pass the state into the <Screen /> component to display it and can manipulate it from the <Buttons /> component without calling the DOM directly (as #Avanthika pointed out in their answer).
class Calculator extends React.Component {
constructor(props) {
super(props)
this.state = {
value: '0'
}
this.handleButtonClick = this.handleButtonClick.bind(this)
}
handleButtonClick(value) {
const { value: currentValue } = this.state;
let newValue;
if (value == '=') {
newValue = eval(currentValue).toString();
} else if (value == 'C') {
newValue = 0;
} else if (value == '+/-' && currentValue != '0') {
newValue = `-(${text})`;
} else if (currentValue === '0') {
newValue = value;
} else {
newValue = currentValue.concat(value);
}
this.setState({ value: newValue });
}
render() {
const { value } = this.state;
return (
<div id="body">
<Screen value={value} />
<Buttons onButtonClick={this.handleButtonClick} />
</div>
)
}
}
....
const Button = ({ value, onClick }) => (
<button type="button" onClick={() => onClick(value)}>
{value}
</button>
)
I have renamed your function add and changed its behaviour. Instead of getting/updating the values to DOM, it uses the state in the <Calculator /> component.
You can see the working code here: https://jsfiddle.net/zvxpkq46/
class Button extends React.Component {
constructor(props) {
super(props);
}
add() {
let value = this.value;
let text = document.getElementByID("screenInput").value;
if (value == "=") {
document.getElementById("screenInput").innerHTML = eval(text).toString();
} else if (value == "C") {
document.getElementById("screenInput").innerHTML = "0";
} else if (value == "+/-" && text != "0") {
document.getElementById("screenInput").innerHTML = `-(${text})`;
} else if (value == "d" || (text.slice(-1) != value && text != "0")) {
document.getElementById("screenInput").innerHTML = text.append(value);
}
}
render() {
return (
<button type="button" value={this.props.value} onClick={() => this.add()}>
{this.props.value}
</button>
);
}
}
Constructor doesn't have any initial state set, we don't need it.
Auto bind your function.
add = (button) => {
let value = this.buttonRef.value;
// rest of your code
}
Change the render this way:
render() {
return (
<button ref={(button) => { this.buttonRef = button; }} type="button" value={this.props.value} onClick={() => this.add()}>
{this.props.value}
</button>
);
}
I also suggest avoiding referencing document directly with document.getElementById in react. Instead manage a state variable.

How to add onclick event to a string rendered by dangerouslysetInnerHtml in reactjs?

I have a string , i.e,
let string= "Hello <b>Click here</b>";
render() {
return (<div dangerouslySetInnerHTML={this.createMarkup(value)}/>
}
createMarkup = value => {
return { __html: value };
};
What I would like is to be able to add an onclick event to the <b> tag perform state manipulations on click.
The underlying problem is where I had a function which was supposed to render whatever is passed by the API. The API would send a string 'Money received for order ID 123', or could be any string that I have no control over. Later, I got a requirement where the item that is bolded must be clickable, so as to perform some actions. I didn't have any other way to solve it.
How can I achieve this?
Caveat: This sounds like an X/Y problem, where the underlying problem (whatever it is) should be solved differently, so that you don't have to add a click handler to a DOM element created via dangerouslySetInnerHTML (ideally, so you don't have to create DOM elements via dangerouslySetInnerHTML at all). But answering the question you asked: (You've clarified the use case; solution #1 below applies and isn't poor practice.)
I don't think you can do that directly. Two solutions I can think of:
Use delegated event handler on the div: Add a click handler on the div, but then only take action if the click passed through the b element.
Use a ref on the div, and then hook the click handler up in componentDidMount and componentDidUpdate (finding the b element within the div via querySelector or similar), something along these lines:
Here's an example of #1:
<div onClick={this.clickHandler} dangerouslySetInnerHTML={this.createMarkup(string)}/>
...where clickHandler is
clickHandler(e) {
// `target` is the element the click was on (the div we hooked or an element
// with in it), `currentTarget` is the div we hooked the event on
const el = e.target.closest("B");
if (el && e.currentTarget.contains(el)) {
// ...do your state change...
}
}
...or if you need to support older browsers without ParentNode#closest:
clickHandler(e) {
// `target` is the element the click was on (the div we hooked or an element
// with in it), `currentTarget` is the div we hooked the event on
let el = e.target;
while (el && el !== e.currentTarget && el.tagName !== "B") {
el = el.parentNode;
}
if (el && el.tagName === "B") {
// ...do your state change...
}
}
...and where you bind clickHandler in the constructor (rather than using a property with an arrow function; why: 1, 2):
this.clickHandler = this.clickHandler.bind(this);
Live Example:
let string = "Hello <b>Click here</b>";
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
clicks: 0
};
this.clickHandler = this.clickHandler.bind(this);
}
clickHandler(e) {
// `target` is the element the click was on (the div we hooked or an element
// with in it), `currentTarget` is the div we hooked the event on
// Version supporting older browsers:
let el = e.target;
while (el && el !== e.currentTarget && el.tagName !== "B") {
el = el.parentNode;
}
if (el && el.tagName === "B") {
this.setState(({clicks}) => ({clicks: clicks + 1}));
}
// Alternative for modern browsers:
/*
const el = e.target.closest("B");
if (el && e.currentTarget.contains(el)) {
this.setState(({clicks}) => ({clicks: clicks + 1}));
}
*/
}
createMarkup = value => {
return { __html: value };
};
render() {
const {clicks} = this.state;
return [
<div>Clicks: {clicks}</div>,
<div onClick={this.clickHandler} dangerouslySetInnerHTML={this.createMarkup(string)}/>
];
}
}
ReactDOM.render(
<Example />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Here's an example of #2, but don't do this if A) You can solve the underlying problem separately, or B) #1 works:
let string = "Hello <b>Click here</b>";
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
clicks: 0
};
this.divRef = React.createRef();
this.hooked = null;
this.clickHandler = this.clickHandler.bind(this);
}
clickHandler() {
this.setState(({clicks}) => ({clicks: clicks + 1}));
}
hookDivContents() {
// Get the b element
const b = this.divRef.current && this.divRef.current.querySelector("b");
// No-op if it's not there or it's the same element we have hooked
if (!b || b === this.hooked) {
return;
}
// Unhook the old, hook the new
if (this.hooked) {
this.hooked.removeEventListener("click", this.clickHandler);
}
this.hooked = this.divRef.current;
this.hooked.addEventListener("click", this.clickHandler);
}
componentDidMount() {
this.hookDivContents();
}
componentDidUpdate() {
this.hookDivContents();
}
createMarkup = value => {
return { __html: value };
};
render() {
const {clicks} = this.state;
return [
<div>Clicks: {clicks}</div>,
<div ref={this.divRef} dangerouslySetInnerHTML={this.createMarkup(string)}/>
];
}
}
ReactDOM.render(
<Example />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Refs are an "escape hatch" giving you direct DOM access. Don't use refs lightly; usually, there's a better choice.
But again: I would solve the underlying problem, whatever it is, differently.
react-html-parser can convert HTML strings into React components.
using transform callback function you can update any tag in HTML string with JSX tag adding any properties and event listeners.
This is how I used it:
ReactHtmlParser(item.value, {
transform: (node) => {
if (node.name === 'a' && node.attribs && node.attribs.href) {
const matched = node.attribs.href.match(/^activity\/([0-9]+)$/i);
if (matched && matched[1]) { // activity id
return <a
href={node.attribs.href}
onClick={(e) => {
e.preventDefault();
this.props.openActivityModal(matched[1]);
}}
>{node.children[0].data}</a>
}
}
}
})
Here is a clean way to achieve your needs. By splitting your string depending on the <br> tag you can end up with an mappable array of text :
class BoldText extends React.Component {
constructor(props) {
super(props)
this.state = {
input: "Money received for order ID <b>123</b>, wow for real, so <b>cool</b> its insane"
}
}
boldClick = ev => {
console.log('clicked !')
}
render() {
const { input } = this.state
const a = input.split('</b>')
const filter = /<b>.*<\/b>/
const text = input.split(filter)
const clickable = filter.exec(input)
//<b onClick={this.boldClick}></b>
return (
<div>
<p>{a.map(t => {
const [text, bold] = t.split('<b>')
return <span>{text}<b onClick={this.boldClick}>{bold}</b></span>
})}
</p>
</div>
)
}
}
ReactDOM.render(<BoldText />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.production.min.js"></script>
<idv id='root'>
This solution should solve the problem you mentioned in the comments of the answer above. You can put your API call in the componentDidMount lifecycle function and change your state from there.
You can make the parent tag a <form> and set the onClick="SomeFunction()".
From the child tag that has the HTML string, set type="button".
let string= "Hello <b type='button'>Click here</b>";
render() {
return (
<form onClick={SomeFunction} dangerouslySetInnerHTML =
{this.createMarkup(value)}/>
}
createMarkup = value => {
return { __html: value };
};

Categories