In React, onMouseEnter or hover is not working as expected - reactjs

I have one image with opacity = 1 at the beginning.
When mouse enters the image, change opacity = 0.5. When mouse leaves the image, change the opacity back.
here is one code:
mouseEnter() {
console.log('mouse enter')
const classname = '.' + this.props.post.code
document.querySelector(classname).classList.add('image-hover-opacity')
}
mouseLeave() {
console.log('mouse leave')
const classname = '.' + this.props.post.code
document.querySelector(classname).classList.remove('image-hover-opacity')
}
render() {
<img src={src} onMouseEnter={::this.mouseEnter} onMouseLeave={::this.mouseLeave} />
}
onMouseEnter and onMouseLeave are fired when mouse enters and leaves the image, respectively, good. But the problem is when I move the mouse inside the image, both onMouseEnter and onMouseLeave are fired.
And I have tried css solution as well, when I hover on image, change the opacity property. But the problem is the same: when I move mouse inside the image, :hover and not hover are fired multiple times.
How to solve this? thanks
UPDATE
There is something in my previous code. Created one jsfiddle, and it works.
sorry guys

Using document.querySelector is not a very React way of thinking. You can try this approach:
Use a div wrapping this img to avoid this weird mouseEnter behavior
Use this.state with opacity
constructor() {
this.state = {
opacity: 1
}
}
mouseEnter() {
console.log('mouse enter')
this.setState({opacity: 0.5})
}
mouseLeave() {
console.log('mouse leave')
this.setState({opacity: 1})
}
render() {
<div style={{opacity: this.state.opacity}}>
<img src={src} onMouseEnter={::this.mouseEnter} onMouseLeave={::this.mouseLeave} />
</div>
}

I really think you can achieve this in CSS only.
So your component should have simple className property and that class should have the definitions for:
.image-hover-opacity:hover {
opacity: 0.5;
}
class Example extends React.Component {
constructor() {
super();
this.state = {};
}
render() {
return(
<img className="image-hover-opacity" src="http://i.imgur.com/PLKabDV.png" />
);
}
}
ReactDOM.render(<Example />, document.getElementById('root'));
.image-hover-opacity:hover {
opacity: 0.5;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Related

Unable to make react-player light prop always true

I have implemented a slider like property. Inside each slide, there is a video and its name. I am using [react-player][1] to display the video thumbnail. Once you click on any of the video a modal will get open and will play the video I have rendered the react-player is that the light property is always true. But it's not working once you click on the video that particular position of the slider loses the light property.
import React, { Component } from 'react'
import IndividualSlider from './IndividualSlider'
import ModalVideo from 'react-modal-video'
import { Modal, Button } from 'antd';
import ReactPlayer from 'react-player/youtube';
export class Experience extends Component {
constructor(){
super();
this.state={
Video:[
{
url:'https://www.youtube.com/embed/H2yCdBIpxGY',
name:'Recurssion'
},
{
url:'https://www.youtube.com/embed/s5YgyJcoUI4',
name:'Array'
},
{
url:'https://www.youtube.com/embed/_C4kMqEkGM0',
name:'DP'
},
{
url:'https://www.youtube.com/embed/VBnbYNksWTA',
name:'Graph'
},
{
url:'https://www.youtube.com/embed/M1q3Pzk2UXs',
name:'Trie'
}
],
modalIsOpen:false,
modalLink:""
}
this.left = this.left.bind(this);
this.right=this.right.bind(this);
this.modalPlay = this.modalPlay.bind(this);
this.handleCancel = this.handleCancel.bind(this);
this.handleOk = this.handleOk.bind(this);
}
handleOk = e => {
console.log(e);
this.setState({
modalIsOpen: false,
});
};
handleCancel = e => {
console.log(e);
this.setState({
modalIsOpen: false,
});
};
modalPlay=(link)=>{
this.setState({
modalIsOpen:true,
modalLink:link
})
}
right=()=>{
let arr = this.state.Video;
let temp = arr[0];
arr.shift();
arr.push(temp);
this.setState({
Video:arr
})
}
left=()=>{
let arr = this.state.Video;
let temp = arr[arr.length-1];
arr.pop();
arr.unshift(temp);
this.setState({
Video:arr
})
}
render() {
return (
<div className="ExperienceAClass">
<div className="OneWeekHeading">
<h2 className="OneWeekCaption">
Experience a class
</h2>
<hr className="MentorsCaptionUnderLine" align="center" width="50%"></hr>
</div>
<Modal
title=""
visible={this.state.modalIsOpen}
onOk={this.handleOk}
onCancel={this.handleCancel}
footer={null}
>
<ReactPlayer className="ModalVideo" url={this.state.modalLink}/>
</Modal>
<div className="EntireSliderWrapper">
<a class="prev" onClick={this.left}>
</a>
<div className="VideoSlider">
{this.state.Video.map((child,index)=>{
return <IndividualSlider modalPlay={this.modalPlay} url={child.url} name=
{child.name}/>
})
}
</div>
<a class="next" onClick={this.right}>
</a>
</div>
</div>
)
}
}
export default Experience
And the IndividualSlider component is as follows:
import React, { Component } from 'react'
import ReactPlayer from 'react-player/youtube';
export class IndividualSlider extends Component {
constructor(){
super();
this.state={
light:true
}
this.onClick=this.onClick.bind(this)
}
onClick=()=>{
let modalPlay=this.props.modalPlay;
modalPlay(this.props.url);
}
render() {
return (
<div className="VideoDetails fade">
<ReactPlayer className="YoutubeVideo" onClick={this.onClick} light =
{this.state.light} url={this.props.url}/>
<p>
{this.props.name}
</p>
</div>
)
}
}
export default IndividualSlider
In the above code, I have made the light prop to be always true. As the slide is clicked this component renders but the thumbnail property is not held.
Also, When the modal closes the video keeps on playing. How to deal with that?
As you can see the video which was played regain it's light={true} once slid but the position where it was when played doesn't imply light={true}
I believe the problem is that because you have two instances of React player, one has the light property passed to it and the other is not. Since you always want the light property to work, pass it as a prop set to true always.
The light property is working in the individual slider, because you are indeed setting it in the individual slider
// Inside IndividualSlider component you have this
<ReactPlayer className="YoutubeVideo" onClick={this.onClick} light =
{this.state.light} url={this.props.url}/>
// remove state it and make it like this, since state is not needed
<ReactPlayer className="YoutubeVideo" onClick={this.onClick} light={true} url={this.props.url}/>
Now you are losing the light when clicking on an individual video, because that video is rendered in the parent component (the Experience component_, and there you are not passing the light prop
// In Experience Component you have this
<ReactPlayer className="ModalVideo" url={this.state.modalLink} />
// change it to
<ReactPlayer className="ModalVideo" url={this.state.modalLink} light={true} />

onMouseMove doesnot work outside of element react

I have an svg element on which I am doing onMouseDown, OnMouseMove and onMouseUp. My problem is that as soon as the user leaves the element while still holding their mouse button down, it does not register the mousemove.
I want to keep the onMouseMove event on even after user leaves the element.
Here is my code:
Class School extents React.Component {
onDragStartCircle = (e) {
//taking the initial state
}
onDragCircle = () {
// draging the element
}
onDragEndCircle = () {
// saving data to the database
}
render() {
return (
<div>
<svg>
<circle
cx={50}
cy={50}
r={10}
fill="red"
onMouseDown={this.onDragStartCircle}
onMouseMove={this.onDragCircle}
onMouseUp={this.onDragEndCircle}
/>
</svg>
</div>
);
}
}
I have also tried onDragStart, onDrag these are not working. I am using es6.
Here is an example of your code, whichs shows how to use a container to register events outside of that circle.
You should consider subscribing to the move event on drag start, and unsubscribing again on drag end, to prevent to much events firing. But this should get you started.
class School extends React.Component {
onDragStartCircle = (e) => {
console.log('drag start')
}
onDragCircle = () => {
console.log('move')
}
onDragEndCircle = () => {
console.log('drag end')
}
render() {
return (
<div class="container"
onMouseMove={this.onDragCircle}
onMouseUp={this.onDragEndCircle}>
<svg>
<circle
cx={50}
cy={50}
r={10}
fill="red"
onMouseDown={this.onDragStartCircle}
/>
</svg>
</div>
);
}
}
ReactDOM.render(
<School />,
document.getElementById("react")
);
.container {
width: 100%;
height: 100%;
}
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

reactjs resetting props for componentWillReceiveProps

First question from my first react project.
I'm trying to figure out how to best effect a component on a specific onClick link, to be able to retrigger this effect and to not have it effected by other links on the page. The first two asks are working, but I can't seem to have other links not effect the component.
I have a DisplayLightbox component on my page accepting a couple values
<div>
<DisplayLightbox
showLightbox = {this.state.showLightbox}
lightboxValue = {this.state.travelCity}
/>
</div>
The link I want to trigger the lightbox is calling a function that sets the state (and sends the prop). This part seems to work fine.
onClick={() => this.showLightbox(el.field_city)}
showLightbox(travelCity){
this.setState({
showLightbox: true,
travelCity: travelCity,
});
}
In my DisplayLightbox component, the componentWillReceiveProps does set state to true, which adds the lb-active class in the div, which, from the css, displays the lightbox div. This seems fine.
class DisplayLightbox extends React.Component {
constructor(props) {
super(props);
this.state = {
showLightbox: false,
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.showLightbox !== this.state.showLightbox) {
this.setState({ showLightbox: nextProps.showLightbox });
}
}
closeLightbox() {
this.setState({
showLightbox: false,
});
}
render() {
var lbActive = (this.state.showLightbox === true) ? "lb-active" : ""
return <div className={"lightbox " + lbActive }>
<div className={"lightbox-close " + lbActive } onClick={() =>
this.closeLightbox()}>CLOSE</div>
Copy in lightbox
</div>;
}
}
Looking into it, I see that since props are not controlled by the component and read-only, once it's set as True and I close the div by setting the state of showLighbox back to false, the nextProps.showLightbox remains true. So, if I close it (closeLightbox) and click a different onClick on my page, it still looks into my component, sees nextProps.showLightbox is still set to TRUE and opens the lightbox.
I only want the lightbox open if that specific link is the one being clicked though. It would seem overkill to have every other link setting the state of showLightbox to false, so I'm guessing I'm not looking at this properly.
Thanks
You could just move your closeLightbox method to upper component and manage showLightbox prop from parent. Then component DisplayLightbox will have 3 props: showLightbox, travelCity and method closeLightbox.
When you move closing lightbox to parent component, event componentWillReceiveProps should be no longer needed.
It would seem overkill to have every other link setting the state of
showLightbox to false, so I'm guessing I'm not looking at this
properly.
Why not configure only the one link you want to turn on / off the lightbox then?
As i see it, a component who gets its active state from the parent or external component, should not bother to manage it in its own state.
You can manage the on / off state in the parent's state and pass down a isOn and onClose event handler to the LightBox.
Once the LightBox was clicked it will invoke the handler passed down to it and the parent will change the state of isOn to false, this will trigger a render with a new prop of isOn for the LightBox this time it's value is false.
While clicking the external link / button the parent will listen to it and change the state of isOn to true, and again isOn will passed down to LightBox with it's shiny new value of true.
Small example:
const cities = ["ny", "tlv", "ark"];
class Button extends React.Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
}
onClick() {
const { item, onClick } = this.props;
onClick(item);
}
render() {
return <button onClick={this.onClick}>{this.props.children}</button>;
}
}
class LightBox extends React.Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
}
onClick() {
const { city, onClick } = this.props;
onClick(city);
}
render() {
const { isOn } = this.props;
const css = `lightBoxStyle ${isOn && "onStyle"}`;
return (
<div
className={css}
onClick={this.onClick}>
|
</div>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
turnedOn: []
};
this.on = this.on.bind(this);
this.off = this.off.bind(this);
}
on(city) {
const { turnedOn } = this.state;
if (turnedOn.find(c => c === city)) {
return;
}
const nextState = [...turnedOn, city];
this.setState({ turnedOn: nextState });
}
off(city) {
const nextState = this.state.turnedOn.filter(c => c !== city);
this.setState({ turnedOn: nextState });
}
render() {
const { turnedOn } = this.state;
return (
<div>
{cities.map((city, i) => {
const isOn = turnedOn && turnedOn.includes(city);
return (
<div style={{ display: "inline-block", margin: "0 10px" }}>
<LightBox city={city} isOn={isOn} onClick={this.on} />
<hr />
<Button item={city} onClick={this.off}>
Close the light!
</Button>
</div>
);
})}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
.lightBoxStyle{
border: 1px solid #eee;
width: 30px;
height: 30px;
text-align: center;
box-shadow: 0 0 4px 1px #222;
border-radius: 50%;
margin: 0 auto;
cursor: pointer;
}
.onStyle{
background-color: #333;
color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Based on the great replies, I took the close out of the child and back to the parent.
I did this by adding a lightbox-button div to the parent
<div className={"lightbox-button " + this.state.showLightbox} onClick={() => this.showLightbox()}></div>
<DisplayLightbox
showLightbox = {this.state.showLightbox}
lightboxValue = {this.state.travelCity} />
This calls the same function showLightbox, that I modified slightly to toggle
showLightbox(travelCity){
this.setState({
showLightbox: !this.state.showLightbox,
travelCity: travelCity,
});
}
Using css, I keep this lightbox-button hidden, unless this.state.showLightbox is true. When that happens, the button displays and, when click, toggles the showLightbox state, thereby removing the lightbox and button.
Not sure if this is the ideal solution, but it seems to be working.

How to perform jQuery slideToggle() equivalent in reactjs?

The basic idea is to produce jQuery's slideToggle() animation in reactjs.
Hiding an element and showing it based on its state is fairly straightforward, but actually animating the height, so it looks like it's sliding up and down, seems to be more complex than I thought in reactjs. I've googled around for this type of animation and cannot find anything.
The closest I've found is people saying use the "max-height" css property and animate with that, however, that requires you to set a max-height on all divs you want to animate. And with responsive content this is just not the right way to go. On one screen the max height needed might be 200, but on mobile maybe 500!
Here is where I am so far, I can easily collapse/expand a component with the state like I said, but how do I expand this to actually animate? And handle mid animation clicks, so it goes back when needed?
The height-0 css class is just this:
.height-0 {
overflow: hidden;
max-height: 0;
}
import React, { Component, PropTypes } from 'react';
export default class CollapsableComponent extends Component {
constructor(props) {
super(props);
this.state = {
collapsed: false
};
}
toggleCollapse(){
this.setState({
...this.state,
collapsed: this.state.collapsed ? false : true;
});
}
render() {
return (
<div class="row">
<div class="col-sm-12">
<h2>Some Title....
<button class="btn btn-default pull-right" onClick={this.toggleCollapse}>
<span class={`fa fa-${collapsed ? 'expand' : 'compress'}`} aria-hidden="true"/>
</button>
</h2>
<div class={`animation-holder${collapsed ? ' height-0' : ''}`} ref={(div) => { this.holderDiv = div;}}>
<p>content here......</p>
</div>
</div>
</div>
);
}
}
The simplest way I can think of is the following: Sandbox
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [isOpen, setIsOpen] = useState(false);
const style = {
overflow: "hidden",
height: isOpen ? 50 : 0,
transition: "2s"
};
return (
<div className="App">
<div style={style}>
<p> Let me slide in and out!</p>
</div>
<button onClick={() => setIsOpen(prev => !prev)}>Slide Toggle</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
If the want the actual height of the component you could retrieve it with the use of the useRef hook like this: ref.current.clientHeight.

How to fade text in, then out

I'm trying to make a notification next appear to a text input to inform the users their text was saved, and then fade that notification text out.
Basically I'm trying to replicate this action, when a corresponding text input is submitted.
$(this).fadeOut().next().fadeIn();
I can't think of any way to fade it in, then out, that isn't absurdly roundabout.
I'm using Redux as well, and would like to use that, but it's not a requirement. Any advice would be appreciated.
You can use CSS to take care of that. Here's a very simple example (not using redux). Use JS to trigger, CSS to style.
class App extends React.Component {
constructor() {
super();
this.state = {
show: false
};
this.showNotification = this.showNotification.bind(this);
}
showNotification() {
// You can use redux for this.
this.setState({
show: true,
});
setTimeout(() => {
this.setState({
show: false,
});
}, 1000);
}
render() {
return (
<div>
<button onClick={this.showNotification}>Save</button>
<Notification show={this.state.show} />
</div>
);
}
}
class Notification extends React.Component {
render() {
return <span className={this.props.show ? 'show' : ''}>Saved!</span>
}
}
ReactDOM.render(<App/>, document.getElementById('View'));
span {
transition: 300ms all ease;
opacity: 0;
will-change: opacity;
}
.show {
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="View"></div>
i know react is really great and all but lets not forget about jquery:
this is a little bit less absurdly round about:
$('#mydiv').fadeOut(3000)

Resources