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>
);
}
Related
class App extends Component {
constructor() {
super()
this.state = { //state is what decribes our app
robot: robot,
searchfield: ''
}
}
onSearchChange = (event) => {
this.setState({ searchfield: event.target.value })
console.log(this.state.robot);
}
render() {
const filteredRobots = this.state.robot.filter( robot => {
return robot.name.toLowerCase().includes(this.state.searchfield.toLowerCase());
})
return(
<div className='tc'>
<h1>ROBOFRIENDS</h1>
<SearchBox searchChange={ this.onSearchChange } />
<CardList robot = { filteredRobots }/>
</div>
);
}
}
I'm trying to enlarge the font size of ROBOFRIENDS,I've tried to create another css file for editing h1 and also tried
<h1 className="style:{fontSize=3em}">ROBOFRIENDS</h1>
But they both don't work. However, when I tried to use the same method for changing the font color and background color, they work!
Looking for someone can help me out with this problem.
You can not add styles with className prop. you have two options:
adding a className to the element and styling that className in css.
or adding style property like this: style={{ fontSize: '3em' }}
I prefer the second one:
style={{ fontSize: '3em' }}
Because like this you can pass variables to this.
But my favorite way is to use styled-components.
https://styled-components.com/
Check this out, this is a very clean way to style in react.js and reuse the stylings.
There are multiple ways. I would recommend installing 'styled-components'.
I have included an example of how you could use it below:-
import styled from 'styled-components';
export const StyledHeading = styled.h1`
font-size: 3em;
`;
class App extends Component {
constructor() {
super()
this.state = {
robot: robot,
searchfield: ''
}
}
onSearchChange = (event) => {
this.setState({ searchfield: event.target.value })
console.log(this.state.robot);
}
render() {
const filteredRobots = this.state.robot.filter( robot => {
return robot.name.toLowerCase().includes(this.state.searchfield.toLowerCase());
})
return(
<div className='tc'>
<StyledHeading>ROBOFRIENDS</StyledHeading>
<SearchBox searchChange={ this.onSearchChange } />
<CardList robot = { filteredRobots }/>
</div>
);
}
}
I have Conditional Rendering component in reactJs. i use latest react version, and use MaterialUi in my application. this component use to show a span with a text and as soon as user click on it, it change to a input with a component of MaterialUi and user can change the field by this component
import React from 'react';
import EditIcon from '#material-ui/icons/Edit';
import TextField from '#material-ui/core/TextField';
import { grey400 } from 'material-ui/styles/colors';
class InlineEditInput extends React.Component {
constructor(props) {
super(props);
this.state = {
hover: false,
edit: false,
value: this.props.children
};
this.textInput = React.createRef();
}
handleClick = event => {
event.stopPropagation();
if (!this.state.edit) {
this.setState({ value: this.props.children });
this.setState({ edit: true, hover: false });
}
};
handleBlur = () => {
this.setState({ edit: false });
if (this.state.value.length > 0 && this.state.value !== this.props.children) this.props.onChange(this.state.value);
else this.setState({ value: this.props.children });
};
handleMouseEnter = () => this.setState({ hover: true });
handleMouseLeave = () => this.setState({ hover: false });
render() {
let { hover, edit, value } = this.state;
const originalValue = this.props.children;
const styles = {
label: { minHeight: '2em', marginTop: '10px' },
editIcon: { width: 20, height: 20, fill: grey400, marginLeft: 8 },
editIconHidden: { width: 20, height: 20, fill: 'none', marginLeft: 8 }
};
const setFocus = () => {
this.textInput.focus();
};
if (!edit)
return (
<div onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
<span onClick={this.handleClick}>{originalValue}</span>
{hover ? <EditIcon style={styles.editIcon} /> : <EditIcon style={styles.editIconHidden} />}
</div>
);
else
return (
<TextField
id="EditField"
ref={input => {
this.textInput = input;
setFocus();
}}
value={value}
onClick={this.handleClick}
onBlur={this.handleBlur}
onChange={event => this.setState({ value:event.target.value })}
/>
);
}
}
export default InlineEditInput;
At first an span with value of originalvalue that comes get from its props of this component, is rendered and by click on this, edit state changed to ture and a TextField component of MaterialUi is rendered and I want to focus on this TextFieldAs soon as it is rendered.
For this purpose, I render a TextField and define its ref property that pass input to a function with name of setFocus and in this function I write focus method.
But when I click on span and re-render of component is occurred, i faced with the error that said :
this2.textInput.focus is not a function
how can i write this component?
Try using componentDidUpdate life cycle hook
componentDidUpdate(prevProps, prevState, snapshot) {
if(this.state.edit)
this.textInput.focus();
}
The reason your method is not getting the input to be focused might be due to the fact that the DOM is not yet inserted when you are actually creating the ref. More like the textInput element is created but it's not appended to the DOM. Just a hunch, not 100% sure.
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.
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>
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.