How to toggle multiple class in ReactJS - reactjs

I have one question, how to use multiple toggle class
Please check my example below
I want to click <TaxItem /> and add some class to that element, and the second click to remove that class
import React, { Component } from "react";
import TaxItem from "./TaxItems/"
import Pentagon from "../../../assets/images/pentagon.png"
class Taxs extends Component {
constructor(props) {
super(props)
this.state = {
taxStatus: false
}
this.handleTaxStatus = this.handleTaxStatus.bind(this);
}
handleTaxStatus(element) {
console.log('sdasa', element)
}
render() {
return (
<div className="taxs">
<TaxItem
image={Pentagon}
name='Item 1'
taxStatus={false}
handleTaxStatus={this.handleTaxStatus(this)}
/>
<TaxItem
image={Pentagon}
name='Item 2'
taxStatus={false}
handleTaxStatus={this.handleTaxStatus(this)}
/>
</div>
)
}
}
export default Taxs
And here you can check button where I have onClick:
import React, { Component } from "react";
class TaxItem extends Component {
render() {
return (
<div className="tax-item" onClick={this.props.handleTaxStatus}>
<div className={this.props.taxStatus ? 'checked on' : 'checked'}><i className="icon icon-check"></i></div>
<img src={this.props.image} alt="Pentagon" />
<p>{this.props.name}</p>
</div>
)
}
}
export default TaxItem
How I can use THIS, something like jQuery.

As I said in the comment, I would suggest you to not use "THIS", which would mean use the refs, because it would lead to edit the DOM directly, which in React should be avoided when you can.
Instead, you could use an array of taxStatus property, one for each TaxItem, and using them as toggle, something like in the following:
class TaxItem extends React.Component {
localHandleClick = (_) => {
this.props.handleClick(this.props.taxStatusIndex);
};
render() {
const {taxStatus, handleClick} = this.props;
return (
<div
className={"button" + (taxStatus ? " checked" : " not-checked")}
onClick={this.localHandleClick} />
);
}
}
class Taxs extends React.Component {
constructor(props) {
super(props);
const taxItemCounter = props.num;
this.state = {
taxesStatus: new Array(taxItemCounter).fill(false)
}
}
handleClick = (i) => {
const taxesStatus = this.state.taxesStatus;
taxesStatus[i] = !taxesStatus[i];
this.setState({taxesStatus});
}
render() {
return (
<div>
{
this.state.taxesStatus.map((status, index) =>
<TaxItem
key={index}
taxStatusIndex={index}
handleClick={this.handleClick}
taxStatus={status} />
)}
</div>
);
}
}
ReactDOM.render(<Taxs num={3} />, document.getElementById('root'));
#import url(https://fonts.googleapis.com/css?family=Montserrat);
body {
font-family: 'Montserrat', sans-serif;
}
.button {
width: 100px;
height: 25px;
background: red;
margin: 10px;
cursor: pointer;
}
.button.checked {
background: green;
}
<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='root'></div>
Anyways, if you DO want to use "THIS" (which again, would mean using the refs), I can provide you an example.

Related

this.props.xxxx is not a function

class UserForm extends React.Component {
constructor(props) {
super(props);
const { user } = props;
}
_cancelForm() {
this.props.onCancel();
}
render() {
return (
<button onClick={this._cancelForm.bind(this)}> Cancel </button>
);
}
}
class UserCreate extends React.Component {
_navigateToLogin() {
console.log("hi")
}
render() {
return (
<div>
<UserForm onCancel={this._navigateToLogin.bind(this)}/>
</div>
);
}
}
ReactDOM.render(
<UserCreate/>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
import React from 'react'
import { withRouter } from 'react-router-dom';
import UserForm from './UserForm'
import UsersService from '../services/UsersService'
class UserCreate extends React.Component{
_navigateToLogin() {
this.props.history.push('/homepage');
}
async _saveUser(user) {
await UsersService.createUser(user);
this._navigateToLogin();
}
render() {
return(
<div>
<UserForm
onCancel={this._navigateToLogin.bind(this)}
onSubmit={this._saveUser.bind(this)}
/>
</div>
);
}
}
export default withRouter(UserCreate)
import React from 'react'
import {
Button
} from '#material-ui/core'
export default class UserForm extends React.Component {
constructor(props) {
super(props);
const { user } = props;
this.state = {
...
}
_handleFormSubmit() {
const user = {
...
};
this.props.onSubmit(user);
}
_cancelForm() {
this.props.onCancel();
}
render () {
return (
<div style={{ width: '100%', height: 'auto', position: 'fixed', minWidth: '100%', minHeight: '100%', backgroundColor: '#50617C' }}>
<Button size="small" onClick={ this._cancelForm.bind(this) }>Back</Button>
<Button size="small" onClick={ this._handleFormSubmit.bind(this) }>Create</Button>
</div>
)
}
}
The error is present when I click the "Back" button on CreateAccountForm, it returns an error that says that the onCancel function is not a function. I'm sending it on the UserCreate by binding and I'm calling it on the function _cancelForm(). I was thinking that the error is that I'm missing something in the constructor according to some react documentation, I used before this method and it worked, right now I don't know what's happening.
The code you posted does not demonstrate the error, below is your code and it works just fine.
class UserForm extends React.Component {
constructor(props) {
super(props);
}
_cancelForm() {
this.props.onCancel();
}
render() {
return (
<button onClick={this._cancelForm.bind(this)}>
cancel
</button>
);
}
}
class UserCreate extends React.Component {
_navigateToLogin() {
console.log('in navigate login');
}
render() {
return (
<div>
<UserForm
onCancel={this._navigateToLogin.bind(this)}
/>
</div>
);
}
}
ReactDOM.render(
<UserCreate />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Can you provide a minimal snippet that reproduces the error you are getting?
You also don't need to bind the handler if you use arrow functions. For example:
_navigateToLogin = () => {//arrow function is automatically bound to this
console.log('in navigate login');
};
and
<UserForm onCancel={this._navigateToLogin} />

How do I reset a field with a button and is there a more concise way of writing this React

I'm learning React and have managed to create a simple bankcard which has a text field and a button. The text field allows the user to type something in and it will appear on a label. This is achieved by a class component called InsertName. This component, I think I understand, receives the changeName function which is passed down from the Parent <Bankcard /> component.
Then it is 'handled' by the handleChange function in the child component <InsertName />. This then successfully copies the text from the text input field to the label.
I also have a reset button which successfully resets the label to blank.
What I want the reset button to also do is to reset the text input field as well.
I've tried creating a separate function outside of all classes to reset the text field but have no idea on how to work this.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
class Bankcard extends React.Component {
constructor(props) {
super(props);
this.changeName = this.changeName.bind(this);
this.resetButton = this.resetButton.bind(this);
this.state = {cardHolderName: ' '}
}
changeName(newName){
this.setState({cardHolderName: newName})
}
resetButton(){
this.setState({cardHolderName: ' '})
}
render() {
const cardDetails = sampleInfo[0];
return (
<div className="cssmainbox">
<InsertName onChange={this.changeName}/>
<div className="csslabel">
<label>{this.state.cardHolderName}</label>
</div>
<div className="cssbutton"></div>
<ResetButton onClick={this.resetButton}/>
<br></br>
<br></br>
<div className="cssmainnum">
{cardDetails.mainnum}
</div>
</div>
)
}
}
// resetTextField = (reset) => {
// const reset = {this.}
// }
const sampleInfo = [
{
mainnum: 123456789,
validthru: "08/19",
vsc: 1234
},
]
class InsertName extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
const name = e.target.value;
this.props.onChange(name);
}
render() {
return (
<div>
<input type="text"
name="theusersname"
onChange={this.handleChange}>
</input>
</div>
)
}
}
class ResetButton extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
const name = e.target.value;
this.props.onClick(name);
}
render() {
return (
<div>
<button onClick={this.handleClick}/>
</div>
)
}
}
ReactDOM.render(<Bankcard />, document.getElementById('root'));
The css if you want to quickly look at it:
.cssmainbox {
width: 600px;
height: 300px;
border: 15px solid green;
padding: 40px;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.cssmainnum {
font-size: 80px
}
.cssvalidthru {
font-size: 20px
}
.cssbutton {
border-radius: 5px;
What I want the reset button to also do is to reset the text input field as well.
Is there a better way to write this whole thing? I'm thinking just using functions instead of classes or because of it's interactivity is a stateful class as a parent and stateless children necessary?
Here your working code
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class Bankcard extends React.Component {
constructor(props) {
super(props);
this.changeName = this.changeName.bind(this);
this.resetButton = this.resetButton.bind(this);
this.state = { cardHolderName: " " };
}
changeName(e) {
this.setState({ cardHolderName: e.target.value });
}
resetButton() {
this.setState({ cardHolderName: " " });
}
render() {
return (
<div className="cssmainbox">
<InsertName
onNameChange={this.changeName}
//you can pass the cardHolderName along with the changeName function.
cardHolderName={this.state.cardHolderName}
/>
<div className="csslabel">
<label>{this.state.cardHolderName}</label>
</div>
<div className="cssbutton" />
<ResetButton onResetClick={this.resetButton} />
</div>
);
}
}
function InsertName(props){
return (
<div>
<input
type="text"
name="theusersname"
onChange={props.onNameChange}
value={props.cardHolderName}
/>
</div>
);
}
function ResetButton(props) {
return (
<div>
<button onClick={props.onResetClick}>Reset</button>
</div>
);
}
ReactDOM.render(<Bankcard />, document.getElementById("root"));
Here is the working fiddle
Hope it will help you.
Edited
Updated InsertName & ResetButton to functional component and updated the fiddle.

react focus lose on contenteditable

I wrote a custom content editable component, it looks like the below
export default class TextEditor extends React.Component {
constructor(props) {
super(props);
this.ref = React.createRef();
}
onChange = (e) => {
let value = e.target.innerHTML;
this.props.onChange(value);
}
render() {
const { enabled , onChange , style, className, value } = this.props;
return (
<div>
<div contentEditable={enabled}
dangerouslySetInnerHTML={{ __html: value }}
ref={this.ref}
onInput={this.onChange}
style={{
...style,
height: '80px',
overflow: 'auto',
cursor: enabled ? 'text' : 'inherit',
}}
className={`form-control form-control-sm ${className}`}
placeholder="Optional Notes..."
/>
</div>
)
}
}
wherever i type something on the content editable the cursor moves to the beginning of the editable area.
it is because the this.props.onChange(value); updates the value outside and a rerender happening. How to prevent cursor reset on rerendering ??
You will need a combination of componentDidMount and shouldComponentUpdate like so:
class TextEditor extends React.Component {
constructor(props) {
super(props);
this.ref = React.createRef();
this.onChange = this.onChange.bind(this);
}
onChange(){
var html = this.ref.current.innerHTML;
if (this.props.onChange && html !== this.lastHtml) {
this.props.onChange({value: html});
}
this.lastHtml = html;
}
shouldComponentUpdate(nextProps){
return nextProps.value !== this.ref.current.innerHTML;
}
componentDidUpdate() {
if ( this.props.value !== this.ref.current.innerHTML ) {
this.ref.current.innerHTML = this.props.value;
}
}
render() {
const { enabled , style, className, value } = this.props;
return (
<div>
<div contentEditable={enabled}
dangerouslySetInnerHTML={{ __html: value }}
ref={this.ref}
onInput={this.onChange}
onBlur={this.onChange}
className="editable"
placeholder="Optional Notes..."
/>
</div>
)
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
this.state = {value: ""};
}
onChange({value}) {
this.setState({value})
}
render(){
return (
<TextEditor enabled={true} onChange={this.onChange} value={this.state.value}/ >
)
}
}
ReactDOM.render( <App/> , document.getElementById('app'));
.editable {
width: 100%;
height: 100px;
border: 1px solid black;
}
<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>

How to change display onclick in React?

I am wondering how to change a display few elements from hide to visible in React. I have 4 section and for each section button. Start section has start button, About section has about button, Skills section has skills button and Contact section has contact button. How to make it when im clicking Start all others sections get instantly display: none and only Skills section is visible? By clicking About button, others get hide (none) and only About is visible? Etc to others sections.
I know that i have to make a handleonclick but idk how.
Should it work with state?
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Start extends Component {
render() {
return (
<div className='start'>
</div>
);
}
}
class About extends Component {
render() {
return (
<div className='about'>
</div>
);
}
}
class Skills extends Component {
render() {
return (
<div className='skills'>
</div>
);
}
}
class Contact extends Component {
render() {
return (
<div className='contact'>
</div>
);
}
}
class Buttons extends Component {
render() {
return (
<div className="buttons">
<button>Start</button>
<button>About</button>
<button>Skills</button>
<button>Contact</button>
</div>
);
}
}
class App extends Component {
render() {
return (
<div className="App">
<Buttons />
<Main />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
<div id="root"></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>
Keep a state activeSection in the parent container called App. Then, pass it as a props to the child section components, About, Skills etc. Also add a method handleToggleSection, which you can call on click to the buttons and change the state activeSection to that corresponding section name. Inside all section components, About, Skills etc., check the current section name. If the name matches, then return the html or return null. Remember, when you return null, that component don't mount. If you want to keep the components mount regardless they are visible or not, then u need to use css classes like show, hide etc.
Here is the demo.
// import React from "react";
// import ReactDOM from "react-dom";
class Start extends React.Component {
get show() {
return this.props.activeSection === "start";
}
render() {
if (this.show) {
return <div className="start"> Start </div>;
} else {
return null;
}
}
}
class About extends React.Component {
get show() {
return this.props.activeSection === "about";
}
render() {
if (this.show) {
return <div className="about"> About </div>;
} else {
return null;
}
}
}
class Skills extends React.Component {
get show() {
return this.props.activeSection === "skills";
}
render() {
if (this.show) {
return <div className="skills"> Skills </div>;
} else {
return null;
}
}
}
class Contact extends React.Component {
get show() {
return this.props.activeSection === "contact";
}
render() {
if (this.show) {
return <div className="contact"> Contact </div>;
} else {
return null;
}
}
}
const Buttons = ({ onToggle }) => (
<div className="buttons">
<button name="start" onClick={onToggle}>
Start
</button>
<button name="about" onClick={onToggle}>
About
</button>
<button name="skills" onClick={onToggle}>
Skills
</button>
<button name="contact" onClick={onToggle}>
Contact
</button>
</div>
);
const Main = ({ activeSection }) => (
<React.Fragment>
<Start activeSection={activeSection} />
<About activeSection={activeSection} />
<Skills activeSection={activeSection} />
<Contact activeSection={activeSection} />
</React.Fragment>
);
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
activeSection: ""
};
this.handleToggleSection = this.handleToggleSection.bind(this);
}
handleToggleSection(e) {
const { name } = e.target;
this.setState(() => ({
activeSection: name
}));
}
render() {
return (
<div className="App">
<Buttons onToggle={this.handleToggleSection} />
<Main activeSection={this.state.activeSection} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
.App {
font-family: sans-serif;
text-align: center;
}
.show {
display: block;
}
.hide {
display: none;
}
<script crossorigin src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<div id="root"></div>
You can use conditional rendering.
selectSection = section => {
this.setState({ section })
}
render() {
return (
<div className="App">
<Buttons onClick={this.selectSection} />
{this.state.section === "start" && <Start>}
{this.state.section === "about" && <About>}
</div>
);
}
Also, instead of the if you can use switch.

Is it possible to change value in element without changing state?

I have code like below;
class Comment extends Component {
constructor(props) {
super(props);
const color = "red";
}
changeColor() {
this.color = "blue";
console.log(this.color);
}
render() {
return(
<div className="CommentPlaceHolder" style={{backgroundColor: this.color}}>
<form id="form1">
<textarea onFocus={this.changeColor} className="comment" id="feed" name="subject" placeholder="Write something.."></textarea>
<button type="submit" form="form1">Paskelbti</button>
</form>
</div>
);
}
}
export default Comment;
I have a textarea inside div container, and I want that when mouse is clicked on textarea, to change div container color. I have tried many things and all failed. Is it possible to do that without states?
A couple things:
First, the way you are declaring the color in the constructor. You are just declaring a local const that won't be accessible from the components other functions. The correct way to declare it would be using this:
super(props);
this.color = "red";
}
Next, in the onFocus event on the text area, you aren't firing the function appropriately. Use the fat arrow to do so, like this:
<textarea onFocus={() => this.changeColor()} className="comment" id="feed" name="subject" placeholder="Write something.."></textarea>
Now... The problem with the fact that you are not using state is that when you are changing the component's attributes, the component doesn't automatically re-render, as it does when you use this.setState. So you will have to force it to re-render. Luckily, there is the this.forceUpdate() function. So in the changeColor function, just call it.
changeColor() {
this.color = "blue";
console.log(this.color);
this.forceUpdate()
}
here is a working version of these changes:
class App extends React.Component {
constructor(props) {
super(props);
this.color = "red";
}
changeColor() {
this.color = "blue";
console.log(this.color);
this.forceUpdate()
}
render() {
return(
<div className="CommentPlaceHolder" style={{backgroundColor: this.color}}>
<form id="form1">
<textarea onFocus={() => this.changeColor()} className="comment" id="feed" name="subject" placeholder="Write something.."></textarea>
<button type="submit" form="form1">Paskelbti</button>
</form>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('app')
);
<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="app"></div>
I would not recommend updating the DOM manually, nor would I recommend calling this.forceUpdate() - that isn't very good practice with React.
Using setState() is the proper way to get the correct result you are going for. For a small, simple app I think you could get away with doing something like this:
import React, { Component } from 'react'
import styled from 'styled-components'
export default class ChangingDiv extends Component {
state = {
bgColor: 'red'
}
handleColorChange = () => {
const { bgColor } = this.state
bgColor === 'red'
?
this.setState({ bgColor: 'blue' })
:
this.setState({ bgColor: 'red' })
}
render() {
const { bgColor } = this.state
return (
<ColorDiv color={bgColor}>
<TextBox
onFocus={this.handleColorChange}
onBlur={this.handleColorChange}
/>
</ColorDiv>
)
}
}
const ColorDiv = styled.div`
width: 100%;
height: 300px;
display: flex;
justify-content: center;
align-items: center;
background-color: ${props => props.color};
`
const TextBox = styled.textarea`
width: 300px;
padding: 20px;
font-size: 16pt;
`
Using styled components you can set a color based on a state prop. Here I am setting the background-color of the ColorDiv to match the bgColor state prop. When it changes, so does the background-color. You could even add a transition duration to the ColorDiv for a bit smoother transition.
If you aren't using styled components you could essentially do the same thing except instead of doing a bgColor state prop you would make it a className. The class name will change as you focus and blur the input box:
import React, { Component } from 'react'
export default class ChangingDiv extends Component {
state = {
className: 'red'
}
handleColorChange = () => {
const { className } = this.state
className === 'red'
?
this.setState({ className: 'blue' })
:
this.setState({ className: 'red' })
}
render() {
const { className } = this.state
return (
<div className={className}>
<textarea
onFocus={this.handleColorChange}
onBlur={this.handleColorChange}
/>
</div>
)
}
}
If you are still not wanting to set the color stately then you could always do the traditional document.getElementById('#colorDiv') and change the color that way. But this will be breaking the rules of React because you will be manipulating the DOM directly.
You can call this.forceUpdate() to force a rerender, but it isn't recommended. Its almost always better to just update the state.
See Docs
To have a change in your UI, component needs to re-render. To re-render a component either your state or props need to change or you need to call forceUpdate (which is not suggested)
The problem with your code, you are changing a static value and this change is not reflecting in your component until it is re-rendered. To change this you can use below sample code.
constructor(props) {
super(props);
this.state = { color: 'red' };
}
changeColor = () => {
this.setState({color: "blue"});
}
render() {
return(
<div className="CommentPlaceHolder" style={{backgroundColor: this.state.color}}>
{/* some other code */}
</div>
);
}

Resources