react change button icon with font awesome unicodes - reactjs

Watch.js
import React from 'react'
import { useEffect, useState } from 'react'
import axios from 'axios'
const Watch = () => {
const [isPlaying, setIsPlaying] = useState(false)
const toggleVideo = () => {
setIsPlaying(!isPlaying)
}
return (
<button id='play' onClick={() => toggleVideo()} className='fa'>{isPlaying ? '' : ''}</button>
)
}
export default Watch
Here I have a simple function that toggles the isPlaying state and changes the button's icon, but the icon is not being displayed instead the unicode is, I tried setting it's innerHTML but it threw errors and said that it is null, what can I do?

JSX does not allow HTML entities as strings, it will escape those values.
// It displays "First · Second"
<div>{'First · Second'}</div>
From the page I linked above, one option is to use unicode escape values (e.g. '\uXXXX') instead:
<button id="play" onClick={() => toggleVideo()} className="fa">
{isPlaying ? "\uf04b" : "\uf04c"}
</button>;

as you said its not working with innerHTML
i tried like this its working.
<button id='play' onClick={() => toggleVideo()} className="fa">
<div dangerouslySetInnerHTML={{__html: `${isPlaying ? '' : '' }`}} />
</button>

Related

React - Show element with click, and hide it by click outside of it and on it

I have to build notification bell with with notification badge (for number of notifications).
When I click on bell, notification badge dissappears, and dropdown list with notifications is shown.
That part is done.
Next, when I click on that dropdown notification list or out of it (anywhere on page) list is closed.
That is also ok.
But when dropdown list is open and I click on notification bell (or its wrapper) list should be closed (hidden again). And that is not working. Also maybe it would be good that notification badge disappears then because list was opened, but toggle by clicking on bell is my main problem here.
Any help is welcome!
Here is my code:
import { useState, useEffect, useRef } from 'react';
import { Effect } from 'react-notification-badge';
import NotificationBadge from 'react-notification-badge/lib/components/NotificationBadge';
import logoIcon from '../images/logo.svg';
import notificationIcon from '../images/notification.svg';
const TopBar = () => {
const [notifBadgeIsShown, setNotifBadgeShown] = useState(false);
useEffect(() => {
document.addEventListener('click', handleClick, true);
});
const refOne = useRef(null);
const handleClick = (e) => {
if (!refOne.current.contains(e.target)) {
setNotifBadgeShown(false);
}
if (refOne.current.contains(e.target)) {
setNotifBadgeShown(false);
}
};
const notifications = ['Notification 1', 'Notification 2'];
let listItems = notifications.map((number) => (
<li key={number.toString()}>{number}</li>
));
return (
<div className="top-bar">
<img className="logo-icon" src={logoIcon} alt="Logo icon" />
<div
className="notification-wrapper"
onClick={() =>
notifBadgeIsShown === false
? setNotifBadgeShown(true)
: setNotifBadgeShown(false)
}
>
{!notifBadgeIsShown ? (
<NotificationBadge
className="notif-badge"
count={notifications.length}
effect={Effect.SCALE}
/>
) : null}
{notifBadgeIsShown ? <div className="dropdown">{listItems}</div> : null}
<img
className="notification-icon"
src={notificationIcon}
alt="Notification icon"
ref={refOne}
/>
</div>
</div>
);
};
export default TopBar;
I have try to do this with useRef, but still no desired result...

Re-Rendering a component

I'm doing a simple todo list using React. What I fail to do is to remove an item once I click on the button.
However, if I click delete and then add a new item, it's working, but only if I add a new todo.
Edit:I've edited the post and added the parent componenet of AddMission.
import React,{useState}from 'react';
import { Button } from '../UI/Button/Button';
import Card from '../UI/Card/Card';
import classes from '../toDo/AddMission.module.css'
const AddMission = (props) => {
const [done,setDone]=useState(true);
const doneHandler=(m)=>{
m.isDeleted=true;
}
return (
<Card className={classes.users}>
<ul>
{props.missions.map((mission) => (
<li className={mission.isDeleted?classes.done:''} key={mission.id}>
{mission.mission1}
<div className={classes.btn2}>
<Button onClick={()=>{
doneHandler(mission)
}} className={classes.btn}>Done</Button>
</div>
</li>
)) }
</ul>
</Card>
);
};
export default AddMission;
import './App.css';
import React,{useState} from 'react';
import { Mission } from './components/toDo/Mission';
import AddMission from './components/toDo/AddMission';
function App() {
const [mission,setMission]=useState([]);
const [isEmpty,setIsEmpty]=useState(true);
const addMissionHandler = (miss) =>{
setIsEmpty(false);
setMission((prevMission)=>{
return[
...prevMission,
{mission1:miss,isDeleted:false,id:Math.random().toString()},
];
});
};
return (
<div className="">
<div className="App">
<Mission onAddMission={addMissionHandler}/>
{isEmpty?<h1 className="header-title">Start Your Day!</h1>:(<AddMission isVisible={mission.isDeleted} missions={mission}/>)}
</div>
</div>
);
}
const doneHandler=(m)=>{
m.isDeleted=true;
}
This is what is causing your issue, you are mutating an object directly instead of moving this edit up into the parent. In react we don't directly mutate objects because it causes side-effects such as the issue you are having, a component should only re-render when its props change and in your case you aren't changing missions, you are only changing a single object you passed in to your handler.
Because you haven't included the code which is passing in the missions props, I can't give you a very specific solution, but you need to pass something like an onChange prop into <AddMission /> so that you can pass your edited mission back.
You will also need to change your function to something like this...
const doneHandler = (m) =>{
props.onChange({
...m,
isDeleted: true,
});
}
And in your parent component you'll then need to edit the missions variable so when it is passed back in a proper re-render is called with the changed data.
Like others have mentioned it is because you are not changing any state, react will only re-render once state has been modified.
Perhaps you could do something like the below and create an array that logs all of the ids of the done missions?
I'm suggesting that way as it looks like you are styling the list items to look done, rather than filtering them out before mapping.
import React, { useState } from "react";
import { Button } from "../UI/Button/Button";
import Card from "../UI/Card/Card";
import classes from "../toDo/AddMission.module.css";
const AddMission = (props) => {
const [doneMissions, setDoneMissions] = useState([]);
return (
<Card className={classes.users}>
<ul>
{props.missions.map((mission) => (
<li
className={
doneMissions.includes(mission.id)
? classes.done
: ""
}
key={mission.id}
>
{mission.mission1}
<div className={classes.btn2}>
<Button
onClick={() => {
setDoneMissions((prevState) => {
return [...prevState, mission.id];
});
}}
className={classes.btn}
>
Done
</Button>
</div>
</li>
))}
</ul>
</Card>
);
};
export default AddMission;
Hope that helps a bit!
m.isDeleted = true;
m is mutated, so React has no way of knowing that the state has changed.
Pass a function as a prop from the parent component that allows you to update the missions state.
<Button
onClick={() => {
props.deleteMission(mission.id);
}}
className={classes.btn}
>
Done
</Button>;
In the parent component:
const deleteMission = (missionId) => {
setMissions(prevMissions => prevMissions.map(mission => mission.id === missionId ? {...mission, isDeleted: true} : mission))
}
<AddMission missions={mission} deleteMission={deleteMission} />

React.js: How to close headlessui Disclosure modal from code?

I encountered an issue trying to close the headlessui Disclosure modal inside the panel.
My goal is to have a button inside the panel which can close the modal.
The way I tried to solve this problem is doing it manually using useRef, but it works partially.
After opening the panel for the first time, you can close the modal but if you try to open it again, it doesn't work. Can't figure out how to solve this issue.
Any help will be appreciated.
Here is the codesandbox link
And here is the code
import { Disclosure } from "#headlessui/react";
import React, { useState, useRef } from "react";
import CloseIcon from "#material-ui/icons/Close";
import ExpandMoreIcon from "#material-ui/icons/ExpandMore";
const App = () => {
const [isClosed, setIsClosed] = useState(false);
const modalRef = useRef(null);
const hideModalHandler = (e) => {
e.preventDefault();
modalRef.current?.click();
setIsClosed(!isClosed);
};
return (
<Disclosure>
{({ open }) => (
<div ref={modalRef}>
<Disclosure.Button>
<span>modal</span>
<ExpandMoreIcon />
</Disclosure.Button>
{!isClosed && (
<Disclosure.Panel>
<CloseIcon onClick={hideModalHandler} />
<div>name</div>
</Disclosure.Panel>
)}
</div>
)}
</Disclosure>
);
};
export default App;
I haven't used headlessui Disclosure but I see that the function hideModalHandler isn't actually hiding but toggling. Did you mean setIsClosed(true) instead of setIsClosed(!isClosed)?
Also, after a quick look at the documentation, have you tried using the close from the headlessui Disclosure? You don't need useRef
Use the state, and wrap the disclosure button into a DIV
with onClick and some ID string to identify what disclosure must be open. Something like this (works for multiple disclosures):
const [keyOfOpenDisclosure, setKeyOfOpenDisclosure] = useState('')
const toggleDisclosure = (key: string) => {
setKeyOfOpenDisclosure((prev) => (prev !== key ? key : ''))
}
...
<Disclosure>
<div onClick={() => toggleDisclosure(someId)}>
<Disclosure.Button>
Text of disclosure button
</Disclosure.Button>
</div>
<Transition
show={someId === keyOfOpenDisclosure}
...

Im building a React App that requires a pdf to download, in the event the (materialUI) download button is clicked, how can I add that functionality?

the profile component contains the following code:
<div className="button_container" style={{display:'flex'}}>
<DownloadButton text={'PDF'} icon={<GetAppIcon />} />
</div>
the button component contains the following code:
import React from 'react'
import { Button } from "#material-ui/core";
import './Button.css'
const DownloadButton = ({text, icon}) => {
return (
<Button onClick={() => { }} className="custom_btn" endIcon={icon ?
(<div className="btn_icon_container" >{icon}</div>) : null}>
<span className="btn_textw">{text}</span>
</Button>
)
}
export default CustomButton
**I've added an onClick event but am having difficulty figuring the simplest way to trigger the file to download, once the button is clicked **
Any comments are appreciated
Turn your button into a link and provide the path to your pdf file
import React from 'react'
import { Button } from "#material-ui/core";
import './Button.css'
const DownloadButton = ({text, icon}) => {
return (
<Button component="a" href="PATH_TO_YOUR_PDF_FILE" className="custom_btn" endIcon={icon ?
(<div className="btn_icon_container" >{icon}</div>) : null}>
<span className="btn_textw">{text}</span>
</Button>
)
}
export default CustomButton
The simplest way to achieve this is to use an HTML anchor and style it like a button.
Download PDF
With material core buttons you need to add the href prop and it will use an anchor tag instead of a button tag.
<Button href="/path/to/file.pdf">Download PDF</Button>
Your download button would look like
const DownloadButton = ({text, icon}) => {
const endIcon = icon ? (<div className="btn_icon_container" >{icon}</div>) : null;
return (
<Button href="file.pdf" className="custom_btn" endIcon={endIcon}>
<span className="btn_textw">{text}</span>
</Button>
)
}

useState, setting icon active and inactive

Hi all I have following code : my code
I have two useStates, they checking if first one is true then they set active icon if false then inactive icon.
const [icon, setIcon] = useState(false);
const [v, setV] = useState(Viber);
function handleClick() {
setIcon(true);
icon ? setV(Viber) : setV(ViberChecked);
setIcon(false);
}
return (
<div className="App">
<img src={v} alt="icon" onClick={handleClick} />
</div>
);
I think it working in right way, but it works only one time, how can I change my state after all clicks, I mean to set inactive then after click from inactive to active and so on.It should be like something as checkbox
Please help me to resolve this issue, thanks.
You literally set icon to true, then check if icon is true, then set icon false. Why is that? Your icon will always be true in this case
You can do something like this instead: (Check the working sandbox )
function handleClick() {
if(icon){
setV(Viber)
setIcon(false)
}else{
setV(ViberChecked);
setIcon(true);
}
}
you can change your code:
import React, { useState, useEffect } from "react";
import "./styles.css";
import Viber from "./viber.svg";
import ViberChecked from "./viberChecked.svg";
export default function App() {
const [icon, setIcon] = useState(true);
const [v, setV] = useState(Viber);
useEffect(() => {
icon ? setV(Viber) : setV(ViberChecked);
})
// function handleClick() {
// setIcon(true);
// icon ? setV(Viber) : setV(ViberChecked);
// setIcon(false);
// }
return (
<div className="App">
<img src={v} alt="icon" onClick={() => setIcon(!icon)} />
</div>
);
}
You are clicking on the icon to make it true
setIcon(icon => !icon)
or
<img src={v} alt="icon" onClick={e => setIcon(!icon )} />
you cannot use the var right away in hooks. maybe add a useEffect that depends on the icon variable.
useEffect(() => {
// do your stuff
}, [icon]);

Resources