How to add css class based on function in React / Next js? - javascript

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

Related

how to call functional component in class based component using onClick event?

i want to show my functional component in class base component but it is not working. i made simpletable component which is function based and it is showing only table with some values but i want to show it when i clicked on Show user button.
import React ,{Component} from 'react';
import Button from '#material-ui/core/Button';
import SimpleTable from "../userList/result/result";
class ShowUser extends Component{
constructor(props) {
super(props);
this.userList = this.userList.bind(this);
}
userList = () => {
//console.log('You just clicked a recipe name.');
<SimpleTable/>
}
render() {
return (
<div>
<Button variant="contained" color="primary" onClick={this.userList} >
Show User List
</Button>
</div>
);
}
}
export default ShowUser;
Why your code is not working
SimpleTable has to be rendered, so you need to place it inside the render method. Anything that needs to be rendered inside your component has to be placed there
On Click can just contain SimpleTable, it should be used to change the value of the state variable that controls if or not your component will be shown. How do you expect this to work, you are not rendering the table.
Below is how your code should look like to accomplish what you want :
import React ,{Component} from 'react';
import Button from '#material-ui/core/Button';
import SimpleTable from "../userList/result/result";
class ShowUser extends Component{
constructor(props) {
super(props);
this.state = { showUserList : false }
this.userList = this.userList.bind(this);
}
showUserList = () => {
this.setState({ showUserList : true });
}
render() {
return (
<div>
<Button variant="contained" color="primary" onClick={this.showUserList} >
Show User List
</Button>
{this.state.showUserList ? <SimpleTable/> : null}
</div>
);
}
}
export default ShowUser;
You can also add a hideUserList method for some other click.
Or even better a toggleUserList
this.setState({ showUserList : !this.state.showUserList});
If you're referring to the method userList then it appears that you're assuming there is an implicit return value. Because you're using curly braces you need to explicitly return from the function meaning:
const explicitReturn = () => { 134 };
explicitReturn(); <-- returns undefined
const implicitReturn = () => (134);
implicitReturn(); <-- returns 134
The problem lies with how you are trying to display the SimpleTable component. You are using it inside the userList function, but this is incorrect. Only use React elements inside the render method.
What you can do instead is use a state, to toggle the display of the component. Like this:
const SimpleTable = () => (
<p>SimpleTable</p>
);
class ShowUser extends React.Component {
constructor(props) {
super(props);
this.state = {showSimpleTable: false};
this.toggle= this.toggle.bind(this);
}
toggle = () => {
this.setState(prev => ({showSimpleTable: !prev.showSimpleTable}));
}
render() {
return (
<div>
<button variant = "contained" color = "primary" onClick={this.toggle}>
Show User List
</button>
{this.state.showSimpleTable && <SimpleTable />}
</div>
);
}
}
ReactDOM.render(<ShowUser />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
The functionality you are looking for is called Conditional Rendering. The onClick prop function is an event handler and events in react may be used to change the state of a component. That state then may be used to render the components. In normal vanilla javascript or jQuery we call a function and modify the actual DOM to manipulate the UI. But React works with a virtual DOM. You can achieve the functionality you are looking for as follows:
class ShowUser extends Component {
constructor(props) {
super(props)
// This state will control whether the simple table renders or not
this.state = {
showTable: false
}
this.userList.bind(this)
}
// Now when this function is called it will set the state showTable to true
// Setting the state in react re-renders the component (calls the render method again)
userList() {
this.setState({ showTable: true })
}
render() {
const { showTable } = this.state
return (
<div>
<Button variant="contained" color="primary" onClick={this.userList}>
Show User List
</Button>
{/* if showTable is true then <SimpleTable /> is rendered if falls nothing is rendered */}
{showTable && <SimpleTable />}
</div>
)
}
}

Making a section change by clicking a button

i am making a website under react with reactstrap, i have a section that contains charts and a button whose function is to replace said charts with another chart containing more details. however i am struggling to make a concrete code.
i have tried placing the charts in a separate component and have it's content switch through the use of a handleclick function on the button that changes the state of the section (using 'onclick')
i am really not confident in my code's clarity, so i tried reproducing what i did in a simpler matter within fiddle
class hello extends React.Component {
render() {
return (
<h2>hello</h2>
);
}
}
class bye extends React.Component {
render() {
return (
<h2>goodbye</h2>
);
}
}
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<div>
<div>
{this.state.components[hello]}
</div>
<button onClick={this.handleClick}>
switch
{this.setState({components:[<bye />]})}
</button>
</div>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
the div in the "toggle" component is supposed to switch between the components "hello" and "bye"
in effect the current section that is supposed to be displayed ("hello") will be replaced by the other section ("bye") uppon clicking the button under them.
thanks in advance.
If you simply want to toggle between the two components with the button click, you can use conditional rendering.
Change your render method to this:
render(){
return (
<div>
{this.state.isToggleOn?<Hello />:<Bye />}
<button onClick={this.handleClick}>Switch</button>
</div>
}
Also keep your Component's name first character capitalized or react might complain. And using Class based Components is outdated. Hooks are the hot thing right now. So try to use more Functional Components.
Note: My answer assumes you are using babel presets for transpiling jsx and es6 syntax. If not, check out #Colin's answer. It also uses hooks.
why not import all partial views and conditionally render them based on the condition
{condition & <View1/>
There's a few mistakes in your code. Here's an example which does what you want using conditional rendering:
import React, { useState } from "react";
import ReactDOM from "react-dom";
const Hello = () => {
return <h2>hello</h2>;
};
const Bye = () => {
return <h2>bye</h2>;
};
const App = () => {
const [toggled, setToggled] = useState(true);
const handleClick = () => {
setToggled(!toggled);
};
const render = () => {
if (toggled) {
return <Hello />;
}
return <Bye />;
};
return (
<div>
<button onClick={handleClick}>toggle</button>
{render()}
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
There are many ways to do it:
Using conditional operator:
{ this.state.isToggleOn?<Hello/>:<Bye/> }
Using if condition:
render() {
let chart;
if(this.state.isToggleOn) {
chart = <Hello/>;
} else {
chart = <Bye/>;
}
return ( <div> { chart } </div>);
}
3 You can use switch case also for conditional rendering. Here it is not well suited as condition is true or false.

React button radio this.setState is not a function

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>
);
}
}

React JS toggle/ adding a class on hover

I'm using the animate.css library with React and trying to set up a element (button) to pulse when hovered over. Tried to look through the docs and here but can't find a way to achieve this simple task. If anyone has achieved this or found a reference would greatly be appreciated.
class App extends Component {
constructor(props) {
super(props);
this.handleHover = this.handleHover.bind(this);
}
handleHover(){
this.setState({
isHovered: !this.state.isHovered
});
}
render() {
const btnClass = this.state.isHovered ? "pulse animated" : "";
return (
<div>
<button className={btnClass} onMouseEnter={this.state.handleHover} onMouseLeave={this.state.handleHover}>Test</button>
</div>
);
}
}
export default App;
You can use the onMouseEnter and onMouseLeave events on the component and toggle the class accordingly.
constructor(){
super();
this.state = {
isHovered: false
};
this.handleHover = this.handleHover.bind(this);
}
handleHover(){
this.setState(prevState => ({
isHovered: !prevState.isHovered
}));
}
render(){
const btnClass = this.state.isHovered ? "pulse animated" : "";
return <button className={btnClass} onMouseEnter={this.handleHover} onMouseLeave={this.handleHover}></button>
}
Update 05/07/19: Hooks
import React, { useState } from 'react';
export default function Component () {
const [hovered, setHovered] = useState(false);
const toggleHover = () => setHovered(!hovered);
return (
<button
className={hovered ? 'pulse animated' : ''}
onMouseEnter={toggleHover}
onMouseLeave={toggleHover}
>
</button>
)
}
What about using the css :hover property? This worked way better for me by changing my hover class section in the css file to use :hover instead of react.
I tried using the above suggestions but react didn't seem fast enough to get it so the state would become wrong if the mouse moved slowly over the button.

React show image if state is set to true

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>
)
}

Categories