Getting error on React Component on Render - reactjs

As I an New to ReactJS.
What i am doing is when i type is any field State should be update in particular field -
As This is my LoginComponet and Setting small Form -
import React, { Component } from 'react';
import '../css/style.css';
export class LoginCompoent extends Component {
constructor(props) {
super(props);
this.state = {
field: {
phone: {
value: '',
validations: [],
errors: []
},
password: {
value: '',
validations: [],
errors: []
}
}
};
this.handelChangeEvent = this.handelChangeEvent.bind(this);
}
componentDidMount() {
}
handelChangeEvent(event) {
this.setState({
field: {
[event.target.id]: {
'value': event.target.value
}
}
});
}
render() {
console.log(this.state);
return (
<div className="loginMainDiv" >
<div className="">
<input className="login_inp" placeholder="Mobile Number"
value={this.state.field.phone.value}
onChange={this.handelChangeEvent}
type="text" name="phone" id="phone"
/>
<input className="login_inp" placeholder="Password"
value={this.state.field.password.value}
onChange={this.handelChangeEvent}
type="password" name="password" id="password"
/>
<button className="login_btn" >Login Safely</button>
</div>
</div>
);
}
}
Expected Result - on console.log(this.state);
when I type 9 in phone field -
field: {
phone: {
value: '9',
validations: [],
errors: []
},
password: {
value: '',
validations: [],
errors: []
}
}
Getting Result -
field: {
phone: {
value: '9'
}
}
I don't know why all fields are suddenly hidden when i update only phone field. ?
Because of this password is not setting in the form. ERROR - this.state.field.password is undefined ???

Deep merging issues, as you set a name property to your input, this should work:
this.setState(prevState => ({
field: {
...prevState.field,
[event.target.name]: {
'value': event.target.value
}
}
}));

In your handleChangeEvent function, you are updating the value of the field in the state:
this.setState({field: {
[event.target.id]: {
'value': event.target.value
}
}})
This will obviously overwrite the existing value of the field.
In your case, I would recommend using the callback function inside the setState. Please see the docs.
For example, if you want to update the value of the phone but also you want the value of the password to remain unchanged, You could do something like this:
handleChangeEvent = (event) => {
this.setState((prevState) => {
return {field: {
[event.target.id]: event.target.value,
...prevState.field
}
};
});
}

As I have tried all the Above answers but facing the error.
ERROR- Uncaught TypeError: Cannot read property 'id' of null on this.setState( prevState => ( {} ) ).
The Problem was - the reference of event are not maintain in async call that's why event.target is becoming null and getting above Error.
I got the concept of event.persist() which helps to maintain all the references of the event and make the Wrapper to the browser event with async calls.
You can go to this Article Reference

Related

React set state with variable that is nested

I have an input that looks like
<input name="data.company.name" value="Bob's Burgers" />
and on it's onChange I'd like to update the state with it's name.
<input name="data.company.name" value="Bob's Burgers" onChange={(e) => this.setState({ [e.name]: e.target.value}) />
But when I do this the state looks like
this.state = {
data: { company: { name: '' } },
data.company.name: "Bob's Burgers"
}
How can I achieve passing the name to the state so I end up with
this.state = {
data: { company: { name: "Bob's Burgers" } }
}
I cannot alter the name of the input as it's set via a Field Component.
If you don't mind adding lodash to your project you could do this:
<input
name="data.company.name"
value="Bob's Burgers"
onChange={e =>
e.persist();
this.setState(prevState => {
return _.setWith(_.clone(prevState), e.name, e.target.value, _.clone);
});
}
/>;

How to make api in react select

This is my code
My state
this.state = {
loading: true,
weather: [],
cityName: [],
selectedOption: '',
}
My call api
const getAPIcityName = Axios.get('http://dataservice.accuweather.com/locations/v1/topcities/100?').then((res) => {
console.log('res' + res);
this.setState({ cityName: res.AdministrativeArea.LocalizedName });
}, (error) => {
console.log('error', error)
});
}
And here i wont to do the Select the name of the city
handleChange(selectedOption) {
this.setState({ selectedOption });
console.log(selectedOption);
}
render() {
let options = this.state.cityName.map((cityName) => {
return cityName.AdministrativeArea.LocalizedName;
})
return (
<div class="container">
<h1 for="Search">Search</h1>
<form>
<Select
name="form-field-name"
value={this.state.value}
onChange={this.handleChange}
options={options}
/>
And here it works
{/* <select class="custom-select custom-select-lg mb-3">
{this.state.cityName.map(cityName => <option key={cityName.Key}>{cityName.AdministrativeArea.LocalizedName}</option>)}
</select> */}
And this is the Error
Unhandled Rejection (TypeError): Cannot read property 'LocalizedName' of undefined
If my understanding is correct, you are using react-select.
react-select needs options array in the following format,
const options = [
{ value: '', label: '' },
{ value: '', label: '' },
...
]
Your options should be in above format.
As your data is coming from an API, you need to first check if you have data in state and then only iterate over the state to get options
let options = [];
if(this.state.cityName && this.state.cityName.length > 0){
options = this.state.cityName.map((cityName) => {
return {value: cityName.AdministrativeArea.LocalizedName, label: cityName.AdministrativeArea.LocalizedName};
})
}

<Select> component from material-ui not updating changes

The dropdown looks and works fine, but will not update a new selection and I get the following error message:
Warning: Use the `defaultValue` or `value` props on <select> instead of setting `selected` on <option>.
Selected is not set on <option> as far as I'm aware, so it must be set by material-ui's component. Anyway, if I change value into defaultValue, I get the following error message:
aterial-UI: the `value` property is required when using the `Select` component with `native=false` (default).
I thought it was a problem in Material-ui itself, but their example works fine, although there are no parent/child components in the example like mine.
Example:
https://codesandbox.io/s/7yk922om7x
My code (shortened for brevity):
constructor(props) {
super(props)
this.state = {
languageValues: {
htmlFor: 'lstLanguages',
value: 'english',
input: <Input name="language" id="lstLanguages"/>,
options: [
{ value: 'dutch', text: 'Nederlands' },
{ value: 'french', text: 'Français' },
{ value: 'english', text: 'English' },
{ value: 'german', text: 'Deutsch' }],
helperText: 'Choose your language',
}
}
}
handleChange = event => {
event.preventDefault();
this.setState({ [event.target.name]: event.target.value });
}
render() {
return (
<div>
<h2 id="speechTitle">Speech Settings</h2>
<hr/>
<FormGroup column='true'>
<DropDown
dataToFill={ this.state.languageValues }
onChange={ this.handleChange.bind(this) }
/>
Dropdown.js:
const DropDown = ({dataToFill}) => {
const menuItemValueList = dataToFill.options.map((item, i) => {
return <MenuItem value={ item.value } key={ i }>{ item.text }</MenuItem> //Always provide a key
})
return (
<FormGroup column='true'>
<FormControl>
<InputLabel htmlFor={ dataToFill.htmlFor }>Languages</InputLabel>
<Select
defaultValue={ dataToFill.value }
input={ dataToFill.input }
>
{ menuItemValueList }
</Select>
<FormHelperText>{ dataToFill.helperText }</FormHelperText>
</FormControl>
</FormGroup>
);
}
EDIT 1
I think I have found the problem: The handleChange function expects [event.target.name] but the value that needs changing is nested in the state, I'm not sure how I can access it...
Event handler code:
handleChange = event => {
this.setState({ [event.target.name]: event.target.value })
}
Nested state object:
languageValues: {
htmlFor: 'lstLanguages',
value: 'english',
input: <Input name="language" id="lstLanguages"/>,
options: [
{ value: 'dutch', text: 'Nederlands' },
{ value: 'french', text: 'Français' },
{ value: 'english', text: 'english' },
{ value: 'german', text: 'German' }
],
helperText: 'Choose your language',
},

semantic ui react Setting dropdown value to state

how to have dropdowns selected value in state.here is my code iam getting value for name field but dropdown not working, can anyone find out what i am missing?
MyComponent.js
import React,{Component} from 'react';
class MyComponent extends Component{
state={
data:{
name:'',
subject:''
}
}
onChange = e =>
this.setState({
data: { ...this.state.data, [e.target.name]: e.target.value }
},()=>{
console.log(this.state.data);
}
)
render(){
const {data}=this.state;
const subjects= [
{text: '1',value: 'kannada'},
{text: '2', value: 'english'},
{text: '3',value: 'hindhi'}
]
return(
<div>
<Input
name="name"
onChange={this.onChange}
placeholder='Your name ...'
/>
<Dropdown
placeholder='Select Subject'
name="subject"
onChange={this.onChange}
selection
options={subjects}
/>
</div>
)
}
}
export default MyComponent;
how to have selected dropdown value in state?, iam getting changed value for name field but for dropdown not getting.
handleChange = (e, { value }) => this.setState({ value })
Add value prop to Dropdown
render(
const { value } = this.state;
return(
<Dropdown
placeholder='Select Subject'
name="subject"
onChange={this.handleChange}
selection
options={subjects}
value={value}
/>)
)
If anyone is using react hooks and semantic ui react, this is how I got it to work, without having to create a separate change handler function for it.
const options = [
{ key: "1", text: "Speaker", value: "SPEAKER" },
{ key: "2", text: "Event Planner", value: "EVENT_PLANNER" }
];
const [values, setValues] = useState({
firstName: "",
userType: ""
});
const onChange = (event, result) => {
const { name, value } = result || event.target;
setValues({ ...values, [name]: value });
};
<Form.Dropdown
placeholder="I am a.."
name="userType"
label="User Type"
selection
onChange={onChange}
options={options}
value={values.userType}
/>
What kept throwing me off was the 'result' that the onChange function takes as an argument. Since the options are stored as objects in an array, the correct way to access their values is with the 'result' and not 'event.target.'
One more way to use DropDown in React Semantic. it worked perfectly for me.
const options = [
{ key: 'ex1', text: 'Example 1', value: 'Example 1' },
{ key: 'ex2', text: 'Example 2', value: 'Example 2' },
]
Method to set value
handleSelectChange=(e,{value})=>this.setState({stateValue:value})
In Form
<Form.Select fluid label='List Example' options={options}
placeholder='List Example'
value={value}
onChange={this.handleSelectChange} />
You can use the Form.Field also.
For more information.
constructor(props) {
super(props);
this.state={
subject : ""
}
}
handleChange = (e, result) => {
const { name, value } = result;
this.setState({
[name]: value
});
};
render() {
const options = [
{ key: 'ex1', text: 'Example 1', value: 'Example 1' },
{ key: 'ex2', text: 'Example 2', value: 'Example 2' },
];
return(
<div>
<Form>
<Form.Field
placeholder="Subject"
name="subject"
label="Subject"
control={Dropdown}
fluid
selection
onChange={this.handleChange}
options={options}
value={this.state.subject}
/>
</Form>
</div>
);
}

reactjs componentWillUnmount is not being called

I have build a form, where there is dropdown on which selection below fields will be displayed. So say, first optionSet1 was selected for which there was 3 field to be shown. If user changes dropdown to select optionSet2, different set of options will be shown.
But when optionSet2 is being rendered and optionSet1 is removed it should have called componentWillUnmount for the each InputFields rendered previously, which is not the case. This function is never called.
class LeadUpdate extends React.Component {
constructor(props, context) {
super(props, context);
}
_getUpdateFields() {
let fields = this.props.inputFields[this.state.updateType];
return _.map(fields, f => {
_.assignIn(f, {
fieldParentClass: 'form-group col-lg-6',
eventName: this.state.eventName
});
return <InputField config={f} />
});
}
_onChange(id, value) {
this.setState({
optionSet: value
});
}
render() {
return (<div>
<div className="col-lg-5">
<form role="form" className="vymo-form">
<InputField values={this.props.values} onChange={this._onChange.bind(this)} />
</form>
</div>
<div className="row">
<form role="form" className="vymo-form">
{this._getUpdateFields()}
</form>
</div>
</div>)
}
}
Update: I have just realised that componentWillUnmount is being called but the actual problem is with eventListner. I am pasting codes here.
Problem -- I am using nodejs events for getting values from different input fields populated. But when optionSet changes all previous unmounted options are also listening to event.
InputField --
import eventsService from '../../../services/events-service';
class InputField extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
id: this.props.id,
value: this._getInputFieldValue() || '',
valid: true,
errorVisible: false,
errorMessage: ''
};
}
componentWillMount() {
if(this.props.eventName) {
this._subscription = eventsService.emitter.addListener(this.props.eventName, this._validate.bind(this));
}
}
componentWillUnmount() {
if(this.props.eventName) {
eventsService.emitter.removeListener(this.props.eventName, this._validate.bind(this));
}
}
_handleChange(event) {
if(this.props.onChange) {
this.props.onChange.call(null, this.state.id, event.target.value);
}
this.setState({
value: event.target.value
});
}
_getClasses(classes) {
if (classes) {
return classes.join(' ');
}
}
_getInputFieldProps() {
let inputProps = {
value: this.state.value,
type: this.props.type,
placeholder: this.props.placeholder || '',
id: this.props.id,
onChange: this._handleChange.bind(this),
className: this._getClasses(this.props.classes) ? this._getClasses(this.props.classes) + 'form-control' : 'form-control',
maxlength: this.props.maxLength,
disabled: this.props.disabled ? "true" : null,
min: this.props.min,
max: this.props.max,
readOnly: this.props.readonly ? "true" : null,
required: this.props.required
};
return inputProps;
}
_validate(result) {
if (this.props.required && !this.state.value) {
valid = false;
this.setState({
errorVisible: true,
errorMessage: 'this is required field',
valid: false
});
}
if(valid) {
this.setState({
errorVisible: false,
errorMessage: 'this is not a valid phone number',
valid: true
});
}
result.valid &= valid;
result.values.push({
type: this.props.type,
code: this.state.id,
value: this.state.value,
name: this.props.label
});
}
_getInputFieldValue() {
switch (this.props.type) {
case Types.NUMBER:
case Types.EMAIL:
case Types.DECIMAL:
case Types.PHONE:
case Types.TEXT:
return this.props.value;
}
}
render() {
let props = this._getInputFieldProps();
return (<div className={this.props.fieldParentClass}>
<label for={this.props.id}><span>{this.props.label}</span><span>{props.required ? '*' : ''}</span></label>
<input {...props}/>
<span className={this.state.errorVisible ? 'show' : 'hide'}>{this.state.errorMessage}</span>
</div>)
}
}
event service:--
import {EventEmitter} from 'events';
//TODO make this as constant
var emmiter = new EventEmitter();
export default {
emitter: emmiter,
}
I understand this event service is bad, its just was for quickly test this functionality.
The Field component remains mounted, in this case you need to use keys to identify which component has changed, added, or removed:
{this.state.mode === 'custom' ?
<Field
label="A"
name="requested_completes"
type="number"
key="a"
/>
:
<Field
label="B"
name="requested_completes"
type="dropdown"
key="b"
/>
}

Resources