I'm trying to hide an image by default and only show it when element is hovered. I've been able to set the default state etc.. Only issue is creating an if statement that will show and hide the image.
This is the component:
import React from 'react';
import { Link } from 'react-router';
import Eyecon from '../../static/eye.svg';
class Item extends React.Component {
constructor(props) {
super(props);
this.displayName = 'Item';
this.handleHover = this.handleHover.bind(this);
this.state = {
hover: false
};
}
mouseOver() {
this.state.hover = true;
}
mouseOut() {
this.state.hover = false;
}
handleHover() {
console.log("hover");
}
render() {
const { item, i } = this.props;
return (
<div className="grid-box">
<img src={Eyecon}/>
</div>
)
}
}
export default Item;
I've tried a few things, but also want to see what the best practice is.
Thanks for your time
There are multiple ways, I would do it like this:
render() {
const { item, i } = this.props;
return (
<div className="grid-box">
{this.state.hover ? (
<img src={Eyecon} />
) : null}
</div>
)
}
But you could also abstract the image rendering into a separate function and not return anything when needed.
Sitenote: You shouldn't mutate the state directly. Use the this.setState() function. Otherwise the component will not be re-rendered.
Also, may I ask why you're not just using css :hover to achieve this behaviour?
I typically like to handle conditional displaying of content in helper functions, like so:
function renderImage() {
const { hover } = this.state;
if (hover) {
return (
<img src={Eyecon} />
);
}
}
Then, you can just call this function from render()
render() {
const { item, i } = this.props;
return (
<div className="grid-box">
{renderImage.call(this)}
</div>
)
}
Related
I'm using Next js and react visibility sensor to let me know when a div is visible on screen.
Code kinda looks like:
import VisibilitySensor from "react-visibility-sensor";
function onChange(isVisible) {
let colorstate = isVisible ? "test" : "test dark";
console.log(colorstate)
}
export default function Home() {
return (
<VisibilitySensor onChange={onChange}>
<div className={colorstate}>this is a test div.</div>
</VisibilitySensor>
);
}
Changing the div className to the {colorstate} variable doesn't work (returns undefined).
I'm fairly new to React and I tried various answers online using "this.state" methods which all didn't work.
Right now the onChange function works fine and prints the correct class name in the log, I just don't know how to associate it with the div.
Thanks.
You can use useState hook, this is how it would look like with initial className of 'test dark'
import VisibilitySensor from "react-visibility-sensor";
import {useState} from 'react'
export default function Home() {
const [colorState, setColorState] = useState('test dark')
const onChange = (isVisible) => {
isVisible ? setColorState("test") : setColorState("test dark");
}
return (
<VisibilitySensor onChange={onChange}>
<div className={colorState}>this is a test div.</div>
</VisibilitySensor>
);
}
seems your colorState variable is visible only through the onChange.
class Home extends React.Component{
constructor(props){
super(props);
this.state =
{
dark: true
}
}
test = () => {
this.setState(
{
dark: !this.state.dark
}
)
}
render(){
return(
<div className={this.state.dark ? "dark" : "white"} onClick={this.test}>
test
</div>
);
}
}
should work
I have 2 component a parent component to manage the state and a lot of other things and a child component with some reactstrap buttons radio i'm trying to change the state onClick on the child buttons but I get the error: this.setState is not a function and i can't figure out what's wrong with my code =>
//Parent
import React, { Component } from 'react';
import BtnRadio from './btnToggle';
class parent extends Component {
state = {
rSelected: true,
}
onRadioBtnClick(rSelected) {
this.setState({
rSelected:rSelected
});
}
render(){
return (
<div>
<BtnToggle onRadioBtnClick={this.onRadioBtnClick} active={this.state.rSelected}/>
</div>
);
}
};
export default AddAdmin;
//Chlid
import React from 'react';
import { Button, ButtonGroup } from 'reactstrap';
const BtnRadio = (props) => {
return (
<ButtonGroup>
<Button color="light" onClick={() => props.onRadioBtnClick(true)} active={props.active === true}>Enable</Button>
<Button color="light" onClick={() => props.onRadioBtnClick(false)} active={props.active === false}>Disabled</Button>
</ButtonGroup>
);
};
export default BtnRadio;
is there someone who can point me to the right direction i guess that i forgot to bind something...
The problem is, when you're using non-anonymous functions, this gets overridden, and wont refer to the component anymore. Since you're already using class properties, the simple fix, is to keep using the arrow functions, to keep this referencing the component:
onRadioBtnClick = (rSelected) => {
this.setState({
rSelected:rSelected
});
}
See #5 in this medium article, which explains different ways of binding this to keep it referencing the component.
<BtnToggle onRadioBtnClick={() => this.onRadioBtnClick()} active={this.state.rSelected}/>
Arrow function for the rescue.
You should bind the functions your passing like so:
class parent extends Component {
state = {
rSelected: true,
}
onRadioBtnClick(rSelected) {
this.setState({
rSelected:rSelected
});
}
render(){
return (
<div>
<BtnToggle onRadioBtnClick={this.onRadioBtnClick.bind(this)} active={this.state.rSelected}/>
</div>
);
}
}
alternatively, you can bind the functions before passing them in the constructor:
class parent extends Component {
state = {
rSelected: true,
}
constructor() {
super()
this.onRadioBtnClick = this.onRadioBtnClick.bind(this)
}
onRadioBtnClick(rSelected) {
this.setState({
rSelected:rSelected
});
}
render(){
return (
<div>
<BtnToggle onRadioBtnClick={this.onRadioBtnClick} active={this.state.rSelected}/>
</div>
);
}
}
I have two navigation buttons (light version, and dark version) that I want to render on certain pages.
I tried setting the state in the constructor, and generating the link to the images based on the path of the page, but sometimes the wrong link to the image will generated. It seems as though it's getting the state based on the first page that was ever generated. For example, if "home" is supposed to have the light version of the button any other link I click will generate the light version of the logo, unless I refresh. If "about" is supposed to have the dark version of the logo, all other pages I click through will have the dark version, unless I refresh.
Why won't it generate properly while naturally clicking around and navigating through the different pages?
MenuButton.js
import React, { Component } from 'react';
export default class MenuButton extends Component {
constructor() {
super();
this.state = {
logo_url: ''
}
}
componentDidMount() {
let currentPath = window.location.pathname;
if (!currentPath.includes('about') && !currentPath.includes('news')
&& !currentPath.includes('work')) {
this.setState({ logo_url: `${require('../../assets/nav/logo-light.svg')}` });
} else {
this.setState({ logo_url: `${require('../../assets/nav/logo-dark.svg')}` });
}
}
render() {
return (
<div className="menu-btn--cntr">
<img src={this.state.logo_url} />
</div>
)
}
}
You don't need to use state and life cycle.
You can try something like below -
import React, { Component } from 'react';
export default class MenuButton extends Component {
constructor() {
super();
this.state = {
logo_url: ''
}
}
getButton() {
let currentPath = window.location.pathname;
let btnUrl = ''; // or set some default
if (!currentPath.includes('about') && !currentPath.includes('news')
&& !currentPath.includes('work')) {
// this.setState({ logo_url: `${require('../../assets/nav/logo-light.svg')}` });
btnUrl = `${require('../../assets/nav/logo-light.svg')}`;
} else {
// this.setState({ logo_url: `${require('../../assets/nav/logo-dark.svg')}` });
btnUrl = `${require('../../assets/nav/logo-light.svg')}`;
}
return btnUrl;
}
render() {
const btnUrl = this.getButton();
return (
<div className="menu-btn--cntr">
<img src={btnUrl} />
</div>
)
}
}
I have the following react component which creates a list of Tasks.
The code works ok this.props.data and when the data is empty, no Task appears.
I would like to change the code in a way so that if the array is empty a single text
"list empty"
is displayed instead.
I have tried to create a function for listItems and inside add some logic, but I cannot call it from JXS, example <div>{listItems()}</div> although I am not even sure if this is the correct approach.
Any ideas?
import React, { Component } from 'react';
import Task from './Task.js'
class TasksList extends Component {
constructor(props) {
super(props);
}
render() {
const data = this.props.data;
const listItems = data.map(todo => {
return <Task
id={todo.id}
key={todo.id.toString()}
title={todo.title}
onTitleChange={this.props.onTitleChange}
onTaskDelete={this.props.onTaskDelete}
/>
});
return (
<div>{listItems}</div>
)
}
}
export default TasksList;
This should works:
const listItems = data.length == 0 ? "List empty" : data.map(todo => { ... });
You can use something like below, hope this helps.
class TasksList extends Component {
constructor(props) {
super(props);
}
render() {
if(this.props.data.length > 0) {
return (<div>
{data.map(todo => {
return <Task
id={todo.id}
key={todo.id.toString()}
title={todo.title}
onTitleChange={this.props.onTitleChange}
onTaskDelete={this.props.onTaskDelete}
/>
});}
</div>);
}
return (
<div>list empty</div>
)
}
}
export default TasksList;
I have a landing page that contains a logo. I'm trying to get this logo to trigger a change of of state value. The purpose of this is to change from the landing page to the home page on click. I have set it up so that the landing page clear in an determined time, but I want to do this on click. This is my splash.js file that contains the on click function as well as the logo and landing page:
import React, { Component } from 'react';
import Woods from './woods.jpeg';
import Logo1 from './whitestar.png';
export default class Splash extends Component {
constructor() {
super();
this.toggleShowHome = this.toggleShowHome.bind(this);
}
toggleShowHome(property){
this.setState((prevState)=>({[property]:!prevState[property]}))
}
render() {
return(
<div id='Splashwrapper'>
<img src={Woods}></img>
<img id='logoc' src={Logo1} onClick={()=>this.toggleShowHome('showSquareOne')}></img>
</div>
);
}
}
I want the on click function to change the value of splash to false in my App.js file:
import React, { Component } from 'react';
import Splash from './splash';
import Menu from 'components/Global/Menu';
export default class About extends Component {
constructor(){
super();
this.state = {
splash: true
}
}
componentDidMount() {
setTimeout (() => {
this.setState({splash: false});
}, 10000);
}
render() {
if (this.state.splash) {
return <Splash />
}
const { children } = this.props; // eslint-disable-line
return (
<div className='About'>
<Menu />
{ children }
</div>
);
}
}
How can I link the on click function to the App.js file and change the value of splash?
You should define your function toggleShowHome in app.is and pass it as a prop to your splash component. Then you could change your local state in app.js
To make sure I'm understanding, you're looking for the image on the Splash component to trigger a change in the About component?
You can pass a method to your Splash component (from About) that it can call when the image is pressed. So something like this:
render() {
if(this.state.splash) {
return <Splash onLogoClicked={this.logoClicked.bind(this)} />
}
(.......)
}
logoClicked(foo) {
< change state here >
}
And then in your Splash component:
<img id='logoc' src={Logo1} onClick={this.props.onLogoClicked}></img>
Not sure if I understood you well, but you can try this: to pass the on click function from parent (About) to child (Splash), something like this:
YOUR MAIN APP:
export default class About extends Component {
constructor(){
super();
this.state = {
splash: true
}
this.changeSplashState = this.changeSplashState.bind(this);
}
//componentDidMount() {
//setTimeout (() => {
//this.setState({splash: false});
//}, 10000);
//}
changeSplashState() {
this.setState({splash: false});
}
render() {
if (this.state.splash) {
return <Splash triggerClickOnParent={this.changeSplashState} />
}
const { children } = this.props; // eslint-disable-line
return (
<div className='About'>
<Menu />
{ children }
</div>
);
}
}
YOUR SPLASH COMPONENT:
export default class Splash extends Component {
constructor() {
super();
//this.toggleShowHome = this.toggleShowHome.bind(this);
}
toggleShowHome(property){
this.setState((prevState)=>({[property]:!prevState[property]}));
//IT'S UP TO YOU TO DECIDE SETTING TIMOUT OR NOT HERE
//setTimeout (() => {
this.props.triggerClickOnParent();
//}, 10000);
}
render() {
return(
<div id='Splashwrapper'>
<img src={Woods}></img>
<img id='logoc' src={Logo1} onClick={this.toggleShowHome.bind(this,'showSquareOne')}></img>
</div>
);
}
}
Feel free to post here some errors or explain to me more about what you need, but that is the way it should look like, a standard way to pass function as props from parent to child.
You can also read more about how to pass props from parent to child/grandchild/many-deeper-level-child (of course in react's way):
Force React container to refresh data
Re-initializing class on redirect