React-select value not resetting to placeholder text on setState - javascript

I have two react select dropdown and I want the second dropdown to reset and show the placeholder text. I'm setting the stet variable to null when the first dropdown changes. I'm getting the value as null in the backend code, but the value on the ui is not removed. Can some on please help me on how to reset the value in second dropdown and show the placeholder text.
I have some call back functions which will set the options for the two dropdowns. So, please ignore those for now.
import React, {Component} from 'react'
Import Select from 'react-select'
Class test extends Component{
constructor(props){
super(props)
this.state={
val1= null,
val1_options=[],
val2= null,
val2_options=[]
}
this.handleVal1Change = this.handleVal1Change.bind(this)
this.handleVal2Change = this.handleVal2Change.bind(this)
}
}
handleVal1Change(value1) {
this.setState({
val1: value1.value,
val2: null,
val2_options: null
})
}
handleVal2Change(value2) {
this.setState({
val2: value2.value
})
}
render() {
return (
<div>
<Select
placeholder='select val1'
options={this.state.val1_options}
onChange={this.handleVal1Change}
/>
</div>
<div>
<Select
placeholder='select val2'
defaultValue={this.state.val2}
options={this.state.val2_options}
onChange={this.handleVal2Change}
/>
</div>
)
}
export default test

You are using the Select components in uncontrolled mode, which means that the components are not connected to this.state.val1 or this.state.val2. The defaultValue you set for the second component is just used as an initial value. When this.state.val2 is changed in the first component, the second component will not notice the change.
Use value instead of defaultValue:
<Select
placeholder='select val2'
value={this.state.val2}
options={this.state.val2_options}
onChange={this.handleVal2Change}
/>

Related

Clear react-select v2 input field from parent component reactjs?

So, I have parent class, where I press button, and then call 'clearValue' method of TagSelector, where I need to clear AsyncCreatableSelect input.
TagSelector class:
export default class TagSelector extends Component {
constructor(props) {
super(props);
this.state = {
tagDownloaded: []
};
clearValue = () => {
console.log(this.refs.acs);
console.log("here I need to clear AsyncCreatableSelect"); // comment
}
render() {
return (
<AsyncCreatableSelect
ref="acs"
cacheOptions
loadOptions={this.promiseOptions}
isMulti
defaultOptions={this.state.tagDownloaded}
onChange={this.handleChange}
/>
);
}
}
I read api and know that 'clearValue' prop-method can help, but how - I don't know.
React Select feature has option to set select box value - to any of the field / reset as well. Just found below link with working demo , doing reset of select programatically.
Refer it -
How to programmatically clear/reset react-select v2?
https://codesandbox.io/s/8256j5m3vl

Using React, JSX: how to retrieve input value, post it as an element, and then clear it to repeat

This is an assignment for school. It involves using React and JSX to create an input field and a submit button. When the button's clicked, the input value should render as an element to the body. I was able to create it for the first click, but don't know how to repeat it.
If you look at the code below, you'll see that when user types, handleChange changes state of input and when the button's clicked, handleClick changes the boolean state of the button (called 'post'). If post is true, the input along with a timestamp is rendered as a heading.
The problem is that after the render, the input isn't cleared. If the user changes input and clicks button again, it updates the heading with a new timestamp and new input instead of adding another heading.
I've tried changing back state for input and post in handleClick, handleChange, componentDidMount, and componentDidUpdate. But that repeatedly calls setState and I get an error message 'maximum update depth exceeded.'
So, what I want it to do is post a new heading of the input value every time the user clicks the post button. I also want it to clear the input/placeholder text.
import React, { Component } from 'react';
import './App.css';
import Firstposts from './firstposts.jsx';
class App extends Component {
constructor(props) {
super(props)
this.state = {
input: "",
post: false
}
this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleChange(event) {
this.setState({ input: event.target.value });
}
handleClick() {
this.setState({
post: true
})
}
render() {
let timestamp = new Date();
return (
<div className="container">
<div className="panel">
<img height="100 px" src="https://marketing.twitter.com/content/dam/marketing-twitter/brand/logo.png" alt=""></img>
<h1>Chirper</h1>
</div>
<div className="body">
<input
placeholder="type your message here"
onChange={this.handleChange}
/>
<button
onClick={this.handleClick}
>Post</button>
<h2>Log</h2>
{<Firstposts />}
{this.state.post ?
<div>
<h3>{timestamp.toString()}</h3>
<h4>{this.state.input}</h4>
</div>
:
<div />
}
</div>
</div >
);
}
}
export default App;
Update your handleClick method to set posts to an array of posts, instead of a boolean:
handleClick() {
this.setState({
posts: [
...this.state.posts,
this.state.input
]
})
}
This will add the value of this.state.input to the end of this.state.posts, preserving all previous posts.
You can update this further to clear the value of the input field:
handleClick() {
this.setState({
posts: [
...this.state.posts,
this.state.input
],
input: '' // add this line to clear your input field when a new post is submitted
})
}
Also, make sure to give your <input> element a value of this.state.input:
<input
value={this.state.input}
placeholder="type your message here"
onChange={this.handleChange}
/>
Without this, you will not be able to programmatically update the value of the <input> field by using setState. You can read more on uncontrolled components in React.
Then, update your render method to map over this.state.posts and render each one:
{this.state.posts.map(post => (
<h4>{post}</h4>
))}
You can read more on rendering lists in React.

react-dropdown - display will not change if setState is called

I have a React form. I'm using the react-dropdown dependency. I'm having a very strange issue. There is an onChange prop passed to the dropdown component. When is comes back, it sends the value from the dropdown menu back up to the parent component (the form in my case).
One would THINK you could take that response and set its value to the state via this.setState().
Except when I use setState(), in any way, the display value for the select menu stops changing. It shows me my Select your Business text instead of the selected value. If I remove the setState(), it changes.
What.....?
Here is a trimmed down version of the component:
import React from 'react';
import Dropdown from 'react-dropdown'
import FormInput from '../FormInput/FormInput';
import FormCheckbox from '../FormCheckbox/FormCheckbox';
import './RegistrationForm.css'
import 'react-dropdown/style.css'
export default class RegistrationForm extends React.Component {
constructor(props) {
super(props);
this.state={
error_business_name: false,
error_business_email: false,
error_username: false,
error_password: false,
error_type: false,
error_terms: false,
error_policy: false,
email: null,
business_name: null,
username: null,
password: null,
website: null,
terms: false
}
}
handleSelect(e) {
console.log(e.value)
this.setState({ type: e.value })
}
render() {
return (
<main role="main" className="RegistrationForm">
<img alt="Simplr Logo" src={require("../../images/logo.png")} />
<form onSubmit={e => this.handleSubmit(e)}>
<section className={this.state.error_type ? "error" : ""}>
<label htmlFor="type">Type of Business</label>
<Dropdown
className={this.state.error_type ? "dropdown error-dropdown" : "dropdown"}
options={["Law Office", "Accounting Firm", "Construction"]}
// onChange={e => this.setState({ type: e.value })}
onChange={e => this.handleSelect(e)}
placeholder="Select your Business" id="type"
/>
<p className="error-message">Please select a valid business type</p>
</section>
<button>REGISTER</button>
</form>
</main>
)
}
}
handleSelect() gets called on change. If I remove this.setState({ type: e.value }) from that method, the display changes. But if I put it in, I can still get the value, but the display then won't change from the default Select your Business text. The value gets set to the state, but it doesn't appear to be selected to the user.
I have no idea how these two processes are even connected. To my mind, once things are sent off to handleSelect(), the dropdown's job is over. But clearly, the setState() part is impacting the dropdown.
Help!
React dropdown component needs an array of objects as options [{label : "", value : ""}]
So instead of passing a string array pass an array of objects and set whole selected object as state and assign the selected state to value in Dropdown.

Inputs in child component won't update when prop is changing in parent component

I have a shopping list app that is divided to two components as follows:
I implemented those two components as: ShoppingList and:ItemDetails
There is another component: ListItem that represents one item row (with edit and delete buttons).
ShoppinList maps over an array of ListItems.
My App component fetches an initial items array and sends it to ShoppingList.
Each time a click is made on the edit icon in a specific item row I set selectedItem object in my app component and render the ItemDetails component, passing it the selectedItem like so:
toggleDetailsPanel = (itemId) => (e) => {
this.setState((prevState, props) => {
return {
selectedItem: (prevState.selectedItem && prevState.selectedItem.id === itemId) ? null : this.findItemById(itemId),
};
});
};
And in the App render function I render it like that:
<div className={styles.details_outer_container}>
{this.state.selectedItem ? <ItemDetails handleSubmit={this.saveDetails} item={this.state.selectedItem}/> : null}
</div>
Whenever a click is made on the save button I run a function on the app component that updates the item in the items array (saveDetails).
Now I expected the ItemDetails component to render with new values each time I click on a different edit icon in a different item row, but the inputs values won't change, only the title is rendering.
I tried all solutions that I found, involving defaultValue, or setting value with getValue() function, or setting a dynamic key on the inputs, but nothing really helps.
This is my ItemDetails file:
import React from 'react';
import PropTypes from 'prop-types';
import { Grid, Row, Col, input, Button } from 'react-bootstrap';
import styles from './styles.css';
export default class ProductDetails extends React.Component {
static propTypes = {
handleSubmit: PropTypes.func.isRequired,
item: PropTypes.any.isRequired,
};
state = {
id: this.props.item.id,
name: this.props.item.name,
quantity: this.props.item.quantity,
price: this.props.item.price,
description: this.props.item.description,
};
// Set appropriate property in state by input name
handleInputChange = (e) => {
this.setState({
[e.target.name]: e.target.value,
});
};
// Submit changed item to parent component
handleDetailsSubmit = (e) => {
this.props.handleSubmit(this.state);
e.preventDefault();
};
render() {
const item = this.props.item;
const itemName = item.name.toUpperCase() || '';
return (
<div className={styles.details_container}>
<div className="sub_header">
<span>{`${itemName} DETAILS`}</span>
</div>
<form className={styles.form_style}>
<p>
<label>{'Quantity'}</label>
<input type="text" ref="quantity" name="quantity" value={this.state.quantity} onChange={this.handleInputChange} />
</p>
<p>
<label>{'Price'}</label>
<input type="text" ref="price" name="price" value={this.state.price} onChange={this.handleInputChange}/>
</p>
<p>
<label>{'Description'}</label>
<textarea rows={2} ref="description" name="description" value={this.state.description} onChange={this.handleInputChange}/>
</p>
<div className={styles.button_div}>
<Button onClick={this.handleDetailsSubmit} bsStyle="primary" bsSize="small">
{'Save'}
</Button>
</div>
</form>
</`enter code here`div>
);
}
}
I understand this is React's way of handling forms but really don't know how to solve it.
I would really appreciate any help : )
The ProductDetails component only gets its initial values from item. From that point it is all maintained in state. So you need to reset the state when item changes.
Try adding something like this:
componentWillReceiveProps( newProps ) {
if ( this.props.item !== newProps.item ) {
this.setState( {
id: newProps.item.id,
name: newProps.item.name,
quantity: newProps.item.quantity,
price: newProps.item.price,
description: newProps.item.description,
} )
}
}

How to prevent component from updating, if checkbox is checked

A client wants to have a numeric slider component that lets him select a number, and a checkbox that says 'no value'. When the checkbox is checked, the slider should be disabled but should still retain its previously selected configuration.
I'm having trouble implementing this using the idiomatic React way, of Components that have props and state.
I'm envisioning the two as part of a single component, a slider-checkbox, with props like this:
value : number
onChange : (newValue : number) => void
Now, if the no value checkbox is checked, then value is undefined. The problem is that because value also sets the position of the slider, this means the position will be changed once the checkbox is ticked -- and I don't want that to happen.
The problem is while React wants to keep all the components in sync, in this case we don't want to keep the slider in sync with the rest of the application. Even though the value should be undefined (or null), we still want the slider to be sitting on the last value the user picked.
What is the correct way to resolve this issue?
I don't know how your application logic works, since you haven't shared it, however you could use shouldComponentUpdate() to resolve this issue.
If shouldComponentUpdate returns false, then render() will be completely skipped until the next state change. In addition, componentWillUpdate and componentDidUpdate will not be called.
So you could do:
shouldComponentUpdate(nextProps) {
if(typeof nextProps.value === 'undefined') return false; //return false if value is undefined
return true; //otherwise always return true (this is default)
}
This will prevent the component from re-rendering if value is undefined. Though I would suggest sending in null instead, since the variable is actually defined, but has simply no value.
Note that this will not disable the slider as you requested - it will simply maintain the original render-state of the slider.
If you also want to disable the slider when the checkbox is checked, you have a couple of options here as I see it. Here's one:
Split the component into 2 sub-components
The idea here is that the props control the slider and checkbox directly, without the use of a state. This is great if you want to use Stateless Functional Components, check out my guide on how and why to use that.
Demo
So your code would be something like:
CheckboxSlider:
class CheckboxSlider extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
value: 50, //default is in the middle, 50%
disabled: false
};
}
_toggleSlider = () => {
this.setState({disabled: !this.state.disabled});
}
render() {
<div>
<Slider value={this.state.value} disabled={this.state.disabled} />
<CheckBox onCheckboxChange={this._toggleSlider} />
</div>
}
}
export default CheckboxSlider;
Slider:
import React from 'react';
const Slider = (props) => (
<input id="slider" type="range" min="0" max="100" disabled={props.disabled} />
);
export default Slider;
Checkbox:
import React from 'react';
const Checkbox = (props) => (
<input id="checkbox" type="checkbox" onChange={props.onCheckboxChange} />
);
export default Checkbox;
Use separate state to have value of slider input, to enable/disable the slider and to check/uncheck the checkbox. Below is a sample snippet.
class Slider extends React.Component {
constructor(props) {
super(props)
this.state = {
sliderValue: 100,
checkedValue: false,
enable: false
}
}
handleChange= (e) => {
this.setState({sliderValue: e.target.value});
}
handleClick = (e) => {
if(this.state.checkedValue == false) {
this.setState({checkedValue: true, enable: true}, function() {
this.refs.slider.disabled = true;
}.bind(this));
} else if(this.state.checkedValue == true) {
this.setState({checkedValue: false, enable: false});
}
}
render() {
return (
<div>
<input type="range" ref="slider" value={this.state.sliderValue} onChange={this.handleChange} min="100" max="500" step="10" disabled={this.state.enable}/>
<input type="checkbox" onChange={this.handleClick} />
</div>
)
}
}
ReactDOM.render(<Slider />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="app"></div>

Categories

Resources