Kevin Mahendra
Kevin Mahendra

Reputation: 109

How to put a React-Icons into innerHTML?

I'm trying to put a React-Icons into innerHTML of element whenever I clicked it.

like this: target.innerHTML = '<ImCross/>';

But it always failed to show the icons. BUT It will work perfectly if I'm using another element like <span></span> and just put some letters in it. So, is there a way to put an Icon into InnerHtml?

This is the example of my code:

import { ImCross } from "https://cdn.skypack.dev/react-icons/im";

const App = () => {
  const box = {
    backgroundColor: '#000',
    width: 150,
    height: 140
  }
  
  const symbol = {
    color: '#fff',
    textAlign: 'center',
    position: 'relative',
    top: 30,
    fontSize: 70
  }
  
  const handleClickedBox = (e) => {
    const target = e.currentTarget.querySelector('.symbol');
    
    // THIS IS FAILED TO SHOW THE ICON
    target.innerHTML = '<ImCross/>';
    
    // THIS DOESN'T WORK TOO
    target.innerHTML = '<span> <ImCross/> </span>';    

    // BUT THIS ONE IS WORK
    target.innerHTML = '<span>X</span>';
  }
  
  return (
    <div>
      {/* This is the box that will be clicked */}
      <div onClick={(e) => handleClickedBox(e)} style={box}>
        {/* This is element that it's innerHTML will show the symbol */}
        <div className='symbol' style={symbol}></div>
      </div>
    </div>
  )
}

THIS THE NEW CODE WITH MULTIPLE BOXES:

What it's the best way if it's not with innerHTML to show the icon ONLY in clicked box, like in my code here

import { ImCross } from "https://cdn.skypack.dev/react-icons/im";

const App = () => { 
  const boxes = {
      backgroundColor: '#000',
      color: '#fff',
      width: 120,
      height: 120,
    }
   
  const symbol = {
    color: '#fff',
    textAlign: 'center',
    fontSize: 50
  }
  
   const styles = {
      display: 'grid',
      gridTemplateColumns: 'repeat(3, 120px)',
      gap: 10
    }
    
    const handleClickBoard = (e) => {
      // Here, I'm gettin <div> of clicked box
      const clickedBox = e.currentTarget;
      
      // What should i do here to make the children 
         element of clicked element/box show the icon <ImCross />
      
      // I only can achieve what I want by using this
      clickedBox.querySelector('.symbol-on-board').innerHTML = 'X';
    }
   
    let component = [];
    let key = 0;
    
    for (let i = 0; i < 3; i++) {
        for (let j = 0; j < 3; j++) {
            key++;
            component.push(
                {/* This the BOX that wrap the symbol */}
                <div style={boxes} id={key} key={key} onClick={(e) => handleClickBoard(e)}>
                {/* This is where i want the symbol to be shown */}
                    <div style={symbol} className='symbol-on-board'></div>
                </div>
            )
        }
    }
  
    return (
      <div style={styles}>
        {component}
      </div>
    )
}

Upvotes: 1

Views: 1193

Answers (1)

Quentin
Quentin

Reputation: 943193

JSX is not HTML. It gets transformed into a bunch of JavaScript calls by Babel before it goes near the browser.

Don't try to generate React code dynamically. Work with React. Make use of the features it provides, like state.

For example:

const [clicked, setClicked] = useState(false);

const clickHandler = () => { setClicked(current => !current); }

return (
    <div>
        <div onClick={clickHandler} style={box}>
            <div className='symbol' style={symbol}>
                {clicked ? <ImCross/> : "Not clicked yet" }
            </div>
        </div>
    </div>
)

Re comment: A more complex example with multiple boxes.

const [data, setData] = useState([
    { name: "Alice", clicked: false },
    { name: "Bob", clicked: false },
    { name: "Chuck", clicked: false }
]);

return <div>{
    data.map(person => 
        <Person key={person.name} setData={setData} person={person} />
    )
}</div>;

and then

const Person = ({setData, person}) => {
    const clickHandler = () => {
        setData(data => {
            return data.map(item => {
                if (item.name === person.name) {
                    return {
                       ...person,
                       clicked: !person.clicked
                    };
                }
                return person;
            })
        });
    }
    return <div onClick={clickHandler}>
        {person.clicked && <ImCross/>}
        {person.name}
    </div>
} 

Upvotes: 3

Related Questions