How to change image src when onMouseEnter div in react stateless component - javascript

I'm beginner in react.
I want to change my image src when mouse enter the div.
Here is my code.
const CategoryImage = styled.img.attrs(props => ({
src: props.url,
}))`
width: 80px;
height: 80px;
margin: 5px auto;
`;
let imgUrl = ``;
const Category = ({ categoryItems }) => {
function handleHover(category) {
const {
category: { hoverUrl },
} = category;
// console.log(hoverUrl);
imgUrl = hoverUrl;
}
function handleUnHover(category) {
const {
category: { url },
} = category;
// console.log(url);
imgUrl = url;
}
return (
<Container>
<Grid>
{categoryItems.map(category => (
<CategoryContainer
key={category.id}
onMouseEnter={() => handleHover({ category })}
onMouseLeave={() => handleUnHover({ category })}
>
<CategoryImage url={imgUrl} alt={category.name} />
<CategoryName key={category.id}> {category.name} </CategoryName>
</CategoryContainer>
))}
</Grid>
</Container>
);
};
Can I change image without using state?
Most of Questions usually use state to change image. I think state isn't needed when changes occurs in my case(codes) though.
And, I heard that performance usually better without using state. Is that right?
Always Appreciate u guys:)

In case of 2 images , just add css property. Hide it by display none , and position all the images at top ....
On mouse over or enter , in this event , pass the class name , that's it .....
I did this task long back, but can't remember exactly what I had done ,
Try this

Related

Creating like button for multiple items

I am new to React and trying to learn more by creating projects. I made an API call to display some images to the page and I would like to create a like button/icon for each image that changes to red when clicked. However, when I click one button all of the icons change to red. I believe this may be related to the way I have set up my state, but can't seem to figure out how to target each item individually. Any insight would be much appreciated.
`
//store api data
const [eventsData, setEventsData] = useState([]);
//state for like button
const [isLiked, setIsLiked] = useState(false);
useEffect(() => {
axios({
url: "https://app.ticketmaster.com/discovery/v2/events",
params: {
city: userInput,
countryCode: "ca",
},
})
.then((response) => {
setEventsData(response.data._embedded.events);
})
.catch((error) => {
console.log(error)
});
});
//here i've tried to filter and target each item and when i
console.log(event) it does render the clicked item, however all the icons
change to red at the same time
const handleLikeEvent = (id) => {
eventsData.filter((event) => {
if (event.id === id) {
setIsLiked(!isLiked);
}
});
};
return (
{eventsData.map((event) => {
return (
<div key={event.id}>
<img src={event.images[0].url} alt={event.name}></img>
<FontAwesomeIcon
icon={faHeart}
className={isLiked ? "redIcon" : "regularIcon"}
onClick={() => handleLikeEvent(event.id)}
/>
</div>
)
`
Store likes as array of ids
const [eventsData, setEventsData] = useState([]);
const [likes, setLikes] = useState([]);
const handleLikeEvent = (id) => {
setLikes(likes.concat(id));
};
return (
<>
{eventsData.map((event) => {
return (
<div key={event.id}>
<img src={event.images[0].url} alt={event.name}></img>
<FontAwesomeIcon
icon={faHeart}
className={likes.includes(event.id) ? "redIcon" : "regularIcon"}
onClick={() => handleLikeEvent(event.id)}
/>
</div>
);
})}
</>
);
Your issue is with your state, isLiked is just a boolean true or false, it has no way to tell the difference between button 1, or button 2 and so on, so you need a way to change the css property for an individual button, you can find one such implementation by looking Siva's answer, where you store their ids in an array

How to auto hide and show component in react native

In my home screen I want to auto hide my header in 2 seconds, then I will have a button to show the header when pressed. I have tried with HomeStack.Screen but could not achieve it, I have to create my custom header called HeaderHomeComponent.js and imported it on my homescreen, still I could not achieve it. Please I need help on this issue.
Here is my code:
const [showHeader, setShowHeader] = useState(true);
const onRecord = async () => {
if (isRecording) {
camera.current.stopRecording();
} else {
setTimeout(() => setIsRecording && camera.current.stopRecording(), 23*1000);
const data = await camera.current.recordAsync();
}
};
const visibility = () => {
setTimeout(() => setShowHeader(false), 2000);
}
return (
<View style={styles.container}>
<RNCamera
ref={camera}
type={cameraType}
flashMode={flashMode}
onRecordingStart={() => setIsRecording(true)}
onRecordingEnd={() => setIsRecording(false)}
style={styles.preview}
/>
<HeaderHomeComponent />
You can create a function with useeffect.
Make sure you passs show and handleClose functions from Parent. (Example given below).
const MessageBox = (props) => {
useEffect(() => {
if (props.show) {
setTimeout(() => {
props.handleClose(false);
}, 3000);
}
}, [props.show]);
return (
<div className={`messageBox ${props.show ? "show" : null}`}>
{props.message}
</div>
);
};
UseEffect will be called everytime props.show state will change. And we only want our timer to kick in when the show becomes true, so that we can hide it then.
Also, now to use this, it's simple, in any component.
const [showMessageBox, setShowMessageBox] = useState(false);
return(
<MessageBox
show={showMessageBox}
handleClose={setShowMessageBox} />
);
Also, make sure to handle css, part as well for show and hide.
Simple Example below.
.messageBox {
display: none;
}
.messageBox.show {
display: block;
}
Hope this helps, :-)
You need to do something like this as Mindaugas Nakrosis mentioned in comment
const [showHeader, setShowHeader] = useState(true);
useEffect(() => {
setTimeout(() => setShowHeader(false), 2000);
}, []);
In return where your header is present
{
showHeader && <HeaderHomeComponent/>;
}
I think the approach gonna fit "auto hide and show in 2 seconds", is using Animetad opacity, and giving fix height or/and z-index (as fit you) to the element
// HeaderHomeComponent.js
const animOpacity = useRef(new Animated.Value(1)).current // start with showing elem
//change main view to
<Animated.View
style={{ ...yourStyle... ,
opacity: animOpacity,
}}
>
and then for creating the animation somewhere
() => {
Animated.timing(animOpacity, {
toValue: +(!animOpacity), // the numeric value of not current
duration: 2000, // 2 secs
}).start();
}}
The hieraric location of the declaration of the ref should control usage as calling the effect. maybe you can create useEffect inside the header that can determine if it should be visible or not depends navigation or some other props.
hope its helpful!

Automatically close dropdown when a new dropdown is selected/opened (React)

I have a dropdown component and I'd like to be able to automatically close the previous dropdown when you click on a different dropdown menu item. I have the dropdown component working but I can't get them to close after selecting a new item. Additionally I'd like to close the items if you click anywhere on the page. Any help would be greatly appreciated, thanks in advance!
export const Dropdown: FC<Props> = ({ passedBindings }) => {
let [isDropdownOpen, setDropdownOpen] = useState(false);
const [ firstMediaBindings, ...restMediaBindings ] = bindings.mediaFlagBindings||[{}];
const toggleDropdown = () => {
setDropdownOpen(!isDropdownOpen)
};
return (
<div { ...optionalAttributes }>
<Container>
{
firstMoleculeMediaFlag()
}
{isDropdownOpen && restMediaBindings.length > 0 &&
<Container passedBindings={({
padding: {
direction: "all",
size: "size2"
}
})}>
{
restMediaBindings.map((mediaFlagBindings: IMoleculeMediaFlag, index: number) => {
return (
<Container
key={index}
passedBindings={({
padding: {
direction: "all",
size: "size1"
}
})}>
<MediaFlag key={index} passedBindings={mediaFlagBindings} />
</Container>
)
})
}
</Container>
}
</Container>
</Container>
</div>
)
``
You need a backdrop DIV to allow click and exit anywhere on the page.
It's like a 3-layer system.
1st : your page content
2nd : the backdrop goes on top
3rd : your dropdown goes on top of the backdrop
An example (using styled-components for style, but you can style as you wish):
Backdrop.js
This renders a div on top of your page content.
const Backdrop = styled.div`
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.2);
z-index: 100;
`;
Use it like that: conditionally with isDropdownOpen
Dropdown.js
But remember to style your dropdown with a z-index with something higher than the z-index you used on the backdrop. In this example, I used 100 for the backdrop so you can use 200.
export const Dropdown() {
...
return(
isDropdownOpen ?
<Backdrop onClick={toggleDropdown}/>
// Here goes the rest of your return for your dropdown
);
}
If you need one dropdown to close the previous when they are clicked you need something in your state that tells you which one is opened.
Something like:
const [indexDropdownOpened, setIndexDropdownOpened] = useState(false);
You can set it to false (initial value) when no dropdown is opened, and you can set it with an index (or key) to tell your component which one is openend.
On each dropdown, when you render them:
...
return(
<Container
key={index}
onClick={()=>setIndexDropdownOpened(index)}
/>
);
Then, on the backdrop, you could do:
<Backdrop onClick={()=>setIndexDropdownOpnened(false)}/> // So it closes the dropdown

How to make hover event on single component?

I want to display h4 photo title on photo, but only if photo hovered. I was trying do this using onMouseEnter and onMouseLeave, but if I using many the same components, and when I hovered one of them, every components on page displaying photo title. Can I do something in my code to display title only on hovered photo?
Single Photo:
const Photo = props => (
<div onMouseEnter={props.onMouseEvent}
onMouseLeave={props.onMouseEvent}
style={props.backgroundImage}>
<h4>{props.hovered && props.title}</h4>
</div>
);
Displaying many Photo components:
class Gallery extends Component {
state = {
photos: [], // fetched photos here
hovered: false
};
toggleMouseHover = () => this.setState(prev => ({ hovered: !prev.hovered }));
render() {
return (
{this.state.photos.map(photo => {
<Photo
backgroundImage={{ backgroundImage: `url(${photo.src})` }}
title={photo.title}
onMouseEvent={this.toggleMouseHover}
hovered={this.state.hovered}
/>
})}
);
}
}
I was thinking about using content in CSS ::before or ::after, but I can not do it in React.
You can do this with pure css, it shouldn't matter that you are using react.
Single Photo:
const Photo = props => (
<div style={props.backgroundImage} className="div-photo">
<h4 className="photo-title">{props.title}</h4>
</div>
);
Css:
div.div-photo:hover > h4.photo-title {
display: block;
}
div.div-photo > h4.photo-title {
display: none;
}
I think this should work. You can use attribute visibility if you prefer it. Also, as mentioned in the comments, attribute opacity is a good option if you want to use fade-in/fade-out effects.

Hypertexting by pasting a link using a toolbar

I have to say I started Javascript and React this week so I am not really familiar with it yet or with anything in the front end.
I have a link button in side a toolbar. I want to be able to click it, opening a text box where I can write a link, and then the text is hypertexted with it. Just want to say that any tip is appreciated.
Something like the following pictures.
I have coded the toolbar already and am using the slate-react module for the Editor (the text editor used). I am trying to follow what was done in a GitHub example, which is not exactly the same.
So, in essence, it is a link component inside a toolbar, which is inside a "Tooltip" component (that contains the horizontal toolbar plus another vertical bar), which is inside the editor.
My question is: How do I use react and slate editor to tie the Links together in the toolbar? Does the Link component need a state and onChange function? How can I include the Link component in the toolbar (button group), alongside the other buttons within "const Marks"?
I get that these questions might be basic but I am a beginner and would appreciate explanation.
My created Link component can wrap and unwrap link. When clicked,
onClickLink = event => {
event.preventDefault()
const { value } = this.state
const hasLinks = this.hasLinks()
const change = value.change()
if (hasLinks) {
change.call(this.unwrapLink)
}
else
{
const href = window.prompt('Enter the URL of the link:')
change.call(this.wrapLink, href)
}
this.onChange(change)
}
The wrap, unwrap and hasLinks boolean
class Links extends React.Component {
onChange = ({ value }) => {
this.setState({ value })
}
wrapLink(change, href) {
change.wrapInline({
type: 'link',
data: { href },
})
change.moveToEnd() }
unwrapLink(change) {
change.unwrapInline('link') }
hasLinks = () => {
const { value } = this.state
return value.inlines.some(inline => inline.type == 'link')
}
To render it in the editor.
const renderNode = ({ children, node, attributes }) => {
switch (node.type) {
case 'link': {
const { data } = node
const href = data.get('href')
return (
<a {...attributes} href={href}>
{children}
</a>
)
}
The "Tooltip" component, holding MarkSelect (the horizontal toolbar like the one in the picures) and another vertical bar called NodeSelector.
function Tooltip({ onChange, value }: Props) {
return (
<Fragment>
<SelectionPlacement
value={value}
render={({ placement: { left, top, isActive } }) => (
<div
id=...
{
isActive,
},
)}
style={{ left, top }}
>
<NodeSelector onChange={onChange} value={value} />
<MarkSelector onChange={onChange} value={value} />
</div>
)}
/>
The MarkSelector and other Marks (buttons) in the button group.
const MarkSelector = function MarkSelector({ onChange, value }: Props) {
return (
<ButtonGroup className=...>
{Marks.map(({ tooltip, text, type }) => {
const isActive = value.activeMarks.some(mark => mark.type === type);
return (
<Tooltip key={type} title={tooltip}>
<Button
className={classNames({ 'secondary-color': isActive })}
onMouseDown={event => {
event.preventDefault();
const change = value.change().toggleMark(type);
onChange(change);
}}
size=...
style=...
}}
>
{text}
</Button>
</Tooltip>
);
})}
</ButtonGroup>
);
};
const Marks = [
{
type: BOLD,
text: <strong>B</strong>,
tooltip: (
<strong>
Bold
<div className=...</div>
</strong>
),
},
{
type: ITALIC,
text:...
The editor with the tooltip.
render() {
const { onChangeHandler, onKeyDown, value, readOnly } = this.props;
return (
<div
className=...
id=...
style=..
>
{!readOnly && (
<EditorTooltip value={value} onChange={onChangeHandler} />
)}
<SlateEditor
ref=...
className=...
placeholder=...
value={value}
plugins={plugins}
onChange={onChangeHandler}
onKeyDown={onKeyDown}
renderNode={renderNode}
renderMark={renderMark}
readOnly={readOnly}
/>
{!readOnly && <ClickablePadding onClick={this.focusAtEnd} grow />}
</div>
);
}
Although it is not a recommended way to manipulate DOM directly in data-driven frontend frameworks, but you could always get the HTML element of the link, and set its innerHTML (which is the hypertext) according to internal states. This is hacky but it might works.

Categories