ReactJS: Cannot get the length of a string in component state - reactjs

I have a little problem. In my function isLoginOk() it never enters into the if. It enters every time in the else even if my string is longer than 1 char.
When I console.log before the if I can see that my string is longer than 1 yet it doesn't go into the if!
Why is that? (I have verified that the string in my component state is correctly updated by handleChange())
export default class InputLogin extends React.Component {
constructor(props) {
super(props);
this.state = {
login: "",
}
};
handleChange = (e) => {
this.setState({
[e.target.name]: [e.target.value]
});
}
isLoginOk() {
if (this.state.login.length > 1) {
return (<div>OK</div>);
} else {
return (<div>ERROR</div>);
}
}
render() {
return (
<div>
<input type="text" name="login" value={this.state.login} onChange={this.handleChange} /> {this.isLoginOk()}
</div>
);
}
}

It looks like an inconsitency with the way you're setting the component state in handleChange() versus the way isLoginOk() expects the state to be defined.
In the handleChange() function, the "square bracket" syntax [e.target.value] means that you're setting the state value for key [e.target.name] as an array:
this.setState({
// Brackets around [e.target.value] creates array value
[e.target.name]: [e.target.value]
});
The isLoginOk() function however, expects the value to be a string rather than an array:
isLoginOk() {
// You're accessing the string directly and not as an array item
if (this.state.login.length > 1) {
return (<div>OK</div>);
} else {
return (<div>ERROR</div>);
}
}
Consider revising your handleChange() function like so to ensure that the state is updated in a way that is compatible with isLoginOK():
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value // Remove the [ and ] around value
});
}

There is a bug in your code, in your handleChange value.
[e.target.name]: [e.target.value]
You're setting the value of this.state.login to ['some input']. Your validation always fails because you can't get the length of the string inside the array using this.state.login.length. Your validation will return either 0 or 1 based on the array length, certainly not what you intended.
To fix this, remove the brackets around [e.target.value].
class InputLogin extends React.Component {
constructor(props) {
super(props)
this.state = {
login: ""
}
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}
render() {
const { login } = this.state;
const loginResult = login.length > 1 ? "OK" : "ERROR";
return (
<div>
<input type="text" name="login" value={login} onChange={this.handleChange} />
{loginResult}
</div>
)
}
}
ReactDOM.render(<InputLogin />, document.querySelector("#app"))
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>
http://jsfiddle.net/n5u2wwjg/261779/

Remove the brackets around e.target.value
Also simplify the render and get rid of the isLoginOk function. Seems unnecessary.
<input type="text" name="login" value={this.state.login} onChange={this.handleChange} />
<div>{ this.state.login.length > 1 ? 'OK' : 'ERROR' }</div>

Related

Why my component is not changing state when I trigger the function

I am in new in React and I am trying to change the state when the user type some values in the inout. For a reason the component does not seem to work. Could anyone explain me why I am not succeeding in implementing this function? Thanks, Valentino
import React, { Component } from 'react';
class Stake extends Component {
state = ({
userStake: null
});
handleUserStake = (e) => {
e.preventDefault();
let newStake = e.target.value;
this.setState({
userStake: [...userStake, newStake]
})
}
render() {
return (
<div>
<form onSubmit={this.handleUserStake}>
<input
style={{
marginLeft: "40px",
width: "50px"
}}
type="text"
name="stake"
required
/>
</form>
</div >
);
}
}
export default Stake;
to accomplish a controlled input you should add the property value pointing to the respective state, and onChange that will handle its state update. for your onSubmit you use another handler specific to it. you should also fix your handleChange to update its value correctly:
class Stake extends Component {
state = ({
userStake: [],
input: ''
});
handleUserStake = (e) => {
let input = e.target.value;
this.setState({ input });
}
handleSubmit = () => {
e.preventDefault();
let newStake = this.state.input;
this.setState({
userStake: [...this.state.userStake, newStake],
input: '',
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
style={{
marginLeft: "40px",
width: "50px"
}}
type="text"
name="stake"
value={this.state.input}
onChange={this.handleUserStake}
required
/>
</form>
</div>
);
}
}
export default Stake;
You need to first get userStake from the state
handleUserStake = (e) => {
e.preventDefault();
let newStake = e.target.value;
// you need to first get it from the state before updating
const { userStake } = this.state;
this.setState({
userStake: [...userStake, newStake]
})
}
Firstly you should create constructor for your component with state and binded `handleUserStakez method.
Because you are waiting for the submit event from form you would use ref for the input:
this.inputRef = React.createRef();
ref={this.inputRef}
Full code here:
class Stake extends Component {
constructor(props) {
super(props);
this.state = {
userStake: ""
};
this.handleUserStake = this.handleUserStake.bind(this);
this.inputRef = React.createRef();
}
handleUserStake = (e) => {
e.preventDefault();
let newStake = this.inputRef.current.value;
console.log("newStake", newStake);
this.setState({
...this.state,
userStake: newStake
});
};
render() {
return (
<div>
STATE: {this.state.userStake}
<form onSubmit={this.handleUserStake}>
<input
style={{
marginLeft: "40px",
width: "50px"
}}
type="text"
name="stake"
required
ref={this.inputRef}
/>
</form>
</div>
);
}
}
this should work ...
state = {
userStake: [],
};
handleUserStake = (e) => {
e.preventDefault();
let newStake = e.target.stake.value;
this.setState((state) => ({
userStake: [...state.userStake, newStake],
}));
};
what was problem? :-
getting value you need to add NAME from target which is form to get field value. like ...
let newStake = e.target.stake.value;
getting current state value, your were just getting userStake out of nowhere so it was giving undefined error.
this.setState((state) => ({ userStake: [...state.userStake, newStake], }));
make default value to [] for userStake in state obj.
userStake: []
I think I found the solution. The problem was that I had to write [...this.state.userStake, newStake]

Input doesn't change color according to the validation (rcc)

I want to validate the value that the user write in the input.
The browser works, creating a new room with the click of a button works, but the input doesn't change color according to the validation I set, why?
Inside addRoomName function I created setState for the value inside the room input
addRoomName=(e)=> {
this.setState({ room: e.target.value })
and additionally I created setState for the validation with the conditions
this.setState({ addRoomName: e.target.value });
if (e.target.value.length >= 6){
this.setState({roomNameInputColor:'green'})
} else {
this.setState({roomNameInputColor:'red'})
}
Is that may be the problem? because it seems that the react don't even recognize the validation but just the first setState (the one that bring the value that wrote in the room input)
So why the input doesn't change color?
I shared all the code
thanks!
App.js
import React, { Component } from 'react'
import './App.css';
import Addroom from './components/Addroom.js'
import Room from './components/Room.js'
export default class App extends Component {
state = {
roomsList:[{room:'',color:''}],
}
create = (r, c) => {
this.setState({ roomsList: [...this.state.roomsList, { room: r, color: c }] })
}
render() {
return (
<div>
<h1>My Smart House</h1>
{this.state.roomsList.map((element) => {
return <Room r={element.room} c={element.color} />
})}
<Addroom add={this.create}/>
</div>
)
}
}
Addroom.js
import React, { Component } from 'react'
export default class Addroom extends Component {
constructor(props) {
super(props)
this.state = {
roomNameInputColor:'white',
}
}
addRoomName = (e) => {
this.setState({ room: e.target.value })
this.setState({ addRoomName: e.target.value });
if (e.target.value.length >= 6) {
this.setState({ roomNameInputColor: 'green' })
} else {
this.setState({ roomNameInputColor: 'red' })
}
}
addColor = (e) => {
this.setState({ color: e.target.value })
}
createRoom = () => {
this.props.add(this.state.room, this.state.color);
}
render () {
return (
<div>
<input onChange={this.addRoomName} style={{ backgroundInputColor: this.state.roomNameInputColor }} placeholder='Name Your Room'/>
<br/>
<input onChange={this.addColor} placeholder='Whats The Room Color?'/>
<br/>
<button onClick={this.createRoom}>Create</button>
</div>
)
}
}
Room.js
import React, { Component } from 'react'
export default class Room extends Component {
constructor(props) {
super(props)
this.state = {}
}
render() {
return (
<div>
<h1>Room: {this.props.r} </h1>
<h3>Color: {this.props.c} </h3>
</div>
)
}
}
In your addRoomName function, you are doing multiple setState in a row, where it's often a source of state confusions (that you are probably experiencing here).
Prefer to have a single call to the setState() method in your function like this:
addRoomName = (e) => {
const room = e.target.value;
let roomNameInputColor = '';
if (room.length >= 6) {
roomNameInputColor = 'green';
} else {
roomNameInputColor = 'red';
}
this.setState({ room, addRoomName: room, roomNameInputColor });
}
thanks everyone, now it works, I did like you send guys to have effective code and also I changed this
<input onChange={this.addRoomName} style={{backgroundInputColor:this.state.roomNameInputColor}} placeholder='Name Your Room'/><br/>
To this
<input onChange={this.addRoomName} style={{backgroundColor:this.state.roomNameInputColor}} placeholder='Name Your Room'/><br/>
Because backgroundColor is a reserved word and while I tried to fix the problem I didn't saw that little important thing.. thanks!

How to identify input and output elements in React JS?

I have Here React JS Code. with 2 input areas. and 2 output areas. How to link 1 to 1 and 2nd to 2nd.
class MarkdownEditor extends React.Component {
constructor(props) {
super(props);
this.md = new Remarkable();
this.handleChange = this.handleChange.bind(this);
this.state = { value: 'Hello, **world**!' };
this.md2 = new Remarkable();
this.handleChange2 = this.handleChange2.bind(this);
this.state2 = { value: 'Hello, **Brad Pitt**!' };
}
handleChange(e) {
this.setState({ value: e.target.value });
}
handleChange2(e) {
this.setState({ value: e.target.value });
}
getRawMarkup() {
return { __html: this.md.render(this.state.value) };
}
getRawMarkup2() {
return { __html: this.md2.render(this.state2.value) };
}
render() {
return (
<div className="MarkdownEditor">
<h3>Input</h3>
<label htmlFor="markdown-content">
Enter some markdown
</label>
<textarea
id="markdown-content"
onChange={this.handleChange}
defaultValue={this.state.value}
/>
<textarea id="markdown-content2"
onChange={this.handleChange2}
defaultValue={this.state2.value2}
/>
<h3>Output</h3>
<div
className="content"
dangerouslySetInnerHTML={this.getRawMarkup()}
/>
<div
className="content"
dangerouslySetInnerHTML={this.getRawMarkup2()}
/>
</div>
);
}
}
ReactDOM.render(<MarkdownEditor />,
document.getElementById('markdown-example')
);
Is it "Value" that can be changed or "state"? Here only Text area input is used but I do want to use other inputs such as radio, numbers and checkboxes. Moreover Where do I perfrom Arithmatic calculations in code above
You can only use one this.state in your component. It's a javascript object so you can have your two keys inside it:
this.state = { input1: "", input2: "" }
Then, to update the values, you can call this.setState for each key:
handleChange(e) {
this.setState({ input1: e.target.value });
}
handleChange2(e) {
this.setState({ input2: e.target.value });
}
this.setState will update the state by merging the previous state with the object you send him ({input1: e.target.value}) that will cause a rerender of you component with the updated value.
Now in your <textearea>, you must use "value" instead of "defaultValue" and read the value directly from the state i.e. {this.state.input1} for the former and {this.state.input2} for the latter.
This is what we call a controlled component in React.
<input value = {this.state.formValue}>
And you can get or set input's value in other functions of component

Is there a way to set the minimum length of a TextInput in React-Native?

I want to set the minimum length of textInput in React Native, but I couldn't find the event for min length in React Native tutorial.
Is there any way to set the min length of textInput?
Thank you so much.
You can use _onPress like below
_onPress = () => {
if (this.state.value.length < 5) {
Alert.alert('Alert', 'Please type more then 5 words');
return;
}
this.props.onPress(this.ref._lastNativeText);
this.ref.setNativeProps({ text: '' });
}
As commented,
Add a onChange handler and validate value for minimum length
Idea
You will have to add onChange handler to do custom validation as there is no direct way.
In this function, you can check for length and validate it.
Following code also implements following behavior:
Input can accept anything but has minLength is 6.
If input is not valid, border changes to red to signify error.
Error is shown only if input is not being changes (i.e. does not have focus)
Error is not shown if value is completely removed. Just for case when you have optional field.
Sample Fiddle
class MyInput extends React.Component {
constructor(props) {
super(props)
this.state = {
value: '',
isValid: true,
hasFocus: false
}
}
onChange(event) {
const value = event.target.value;
const isValid = value.length >= (this.props.minLength || 0) ||value === ''
this.setState({ value, isValid })
}
onClick() {
this.setState({ hasFocus: true })
}
onBlur() {
this.setState({ hasFocus: false })
}
render() {
const { isValid, hasFocus } = this.state;
return (
<div>
<input
type='text'
className={ isValid || hasFocus ? '' : 'error'}
onChange={ this.onChange.bind(this) }
onClick={ this.onClick.bind(this) }
onBlur={ this.onBlur.bind(this) }
/>
</div>
)
}
}
ReactDOM.render(<MyInput minLength={6} />, document.querySelector("#app"))
.error {
border: 1px solid red;
}
<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>
onChangeText() function, You can do as mentioned below:
const maxLengthInput = set your limit // 60;
const currentLength=this.state.text.length;
this.setState({
textLength: maxLengthInput - currentLength,
text:inputValue
});
So, you can use the this.state.textLength in your component.
The minLength prop is now part of React Native:
use the following in your code.
<TextInput value={this.state.text} minLength={4} />
You're good to go!

Controlled Inputs, displayed values will not update to last digit

i'm using React(Typescript Version) to display some input inside a form.
The problem (as you can see from the image) is that when i update the values, from the setState function, values will not 'scroll' on the right
render() {
return(
<input
name={this.props.input.Name}
type={this.props.input.Type}
defaultValue={this.state.value}
ref={this._input}
key={key()}
)}
The function that updates the Value is a common set Function :
public set Value(data: string) {
this.setState({
internalValue: data,
inputError: !this.validateValue(data)
});
}
Note that the input works as expected if i write from the Keyboard, but if i write the input using a 'simulated' keyboard on screen happens what i just described
Any ideas?
Thank you
Update after simbathesailor support:
render() {
return(
<input
name={this.props.input.Name}
type={this.props.input.Type}
defaultValue={this.state.value}
ref={this._input}
key={key()}
onChange={this.setValue}
/>
)
}
componentDidUpdate(prevProps: InputProps, prevState: InputState) {
if (prevState.value!== this.state.value) {
this._input.current.focus();
}
}
setValue(event: React.ChangeEvent<HTMLInputElement>) {
console.log('change');
this.setState({
value: event.target.value
})
}
shouldComponentUpdate(nextProps: InputProps, nextState: InputState): boolean {
return (this.state.value!= nextState.value);
}
public set Value(data: string) {
this.setState({
value: data,
inputError: !this.validateValue(data)
}, () => {
this._input.current.focus();
});
}
You can use the refs and commit lifecycle method componentDidUpdate method. to achieve this.
In the example mentioned below, it is done for the uncontrolled component. But idea will remain same for controlled component also.
class Test extends React.Component {
constructor(props) {
super(props)
this.InputRef = React.createRef()
this.state = {
value: 0
}
}
setValue = (event) => {
this.setState({
value:event.target.value
})
}
update = () => {
this.setState({
value: (this.state.value || 0) + 1000
})
}
componentDidUpdate(prevProps, prevState) {
if(prevState.value !== this.state.value) {
this.InputRef.current.focus()
}
}
render() {
return (
<div>
<input
value={this.state.value}
onChange={this.setValue}
ref={this.InputRef}
/>
<button onClick={this.update}>update</button>
</div>
)
}
}
ReactDOM.render(<Test />, document.getElementById("root"))
Here is the codepen link to see it working:
Uncontrolled approach(javascript) codepen link
Controlled approach(javascript) codepen link
I have tried typescript for the first time. Thanks for your question :). Typescript is good. And here is your desired solution needed in typescript.
Codesandbox link(Typescript)

Resources