How to print react select state in another component? - reactjs

I am trying to print state of select element in the footer. But the problem is that it does not print anything because the default value is null. And I dont know how to print footer on change of select with state of the select inside.
class SingleColor extends React.Component {
state = {
selectedOption: null,
};
handleChange = selectedOption => {
this.setState({ selectedOption });
};
render() {
const { selectedOption } = this.state;
return (
<React.Fragment>
<h1 className="TITLE">Please choose your favourite colour</h1>
<Select
className="SINGLESELECT"
classNamePrefix="SINGLESELECT__options"
value={selectedOption}
onChange={this.handleChange}
options={options}
styles={customStyles}
/>
<Footer singlevalue={this.state.selectedOption} />
</React.Fragment>
);
}
}
export default class Footer extends Component {
render() {
return (
<div className="bla">
<h1> {this.props.singlevalue}</h1>
</div>
)
}
}

Assuming you are using react-select.
When you change value, react-select give you object as you provided array of object to options.
You should print value in Footer component as,
<h1> {this.props.singlevalue && this.props.singlevalue.label}</h1>
Demo

It’s because onChange event doesn’t send the value directly but an event.
handleChange = event => {
const { value } = event.target
this.setState({ selectedOption: value })
}

Related

Functional Component unable to render return value based on props values

Goal: To implement a Toast Message modal (using Functional Component) which will show or hide based on the props value (props.showToastModal) within the return of ToastModal component
Expected: Using props.showToastModal directly would determine if Toast appears
Actual: Modal does not appear based on props.showToastModal
Here's the code:
Parent Component
class Datasets extends Component {
constructor(props) {
super(props)
this.state = {
showToastModal: false,
toastModalText: ''
}
}
toggleOff = () => {
this.setState({ showToastModal: false, toastModalText: '' })
}
render() {
{this.state.showToastModal && (
<ToastModal
showToastModal={this.state.showToastModal}
toastModalText={this.state.toastModalText}
toggleOff={this.toggleOff}
/>
)}
}
}
Child Component
This works:
const ToastModal = (props) => {
const isOpen = props.showToastModal
return (
<div className={`${css.feedbackModal} ${isOpen ? css.show : css.hide}`}>
{props.toastModalText}
<i
className={`bx bx-x`}
onClick={() => props.toggleOff()}
/>
</div>
)
}
export default ToastModal
But this doesn't (using the props value directly):
const ToastModal = (props) => {
return (
<div className={`${css.feedbackModal} ${props.showToastModal ? css.show : css.hide}`}>
{props.toastModalText}
<i
className={`bx bx-x`}
onClick={() => props.toggleOff()}
/>
</div>
)
}
export default ToastModal
Using a const isOpen = props.showToastModal works as expected instead. I am confused why this happens. Is this is a React Lifecycle issue, or a case where it is bad practice to use props values which may be updated during the render?
Please try destructuring objects
const ToastModal = ({ showToastModal, toggleOff }) => {
return (
<div className={`${css.feedbackModal} ${showToastModal ? css.show : css.hide}`}>
{props.toastModalText}
<i
className={`bx bx-x`}
onClick={toggleOff}
/>
</div>
)
}
export default ToastModal

React onChange function does not fire when passing it down to component

Solved see comment below (Only had to move the Chooser and Section function outside of the class component to get it to work.
So I have a problem with the react onChange function. It does not seem to work when it is passed to a component as props. I tried to pass the component instead of the data but still it did not work. Please consider the following example:
export default class Parent extends Component {
constructor(props) {
super(props)
this.state = {
type: '1',
number: ''
}
}
handleChange = e => {
const { name, value } = e.target
this.setState({ [name]: value })
}
render() {
return (
<div className="App">
<Form
type={this.state.type}
number={this.state.number}
handleChange={this.handleChange}
/>
</div>
}
}
//receiving the props
export default class Child extends Component {
constructor(props) {
super(props)
}
render() {
const Chooser = ({ type, section }) => {
switch (type) {
case '1':
return <Fragment>{section}</Fragment>
default:
return <Fragment>></Fragment>
}
}
const Section = ({ number, handleChange }) => (
<Fragment>
<div>
<label>Number</label>
<input
type='text'
name='number'
placeholder='123456789'
value={number}
onChange={handleChange}
/>
</div>
</Fragment>
)
return (
<Chooser
type={this.props.type}
section={
<Section
number={this.props.number}
handleChange={this.props.handleChange}
/>
}
/>
)
}
}
Interestingly if I put the onChange on the Section level it does work. But this is not what I want since a passed component could have multiple Input functions that I want to pass.
return (
<Chooser
type={this.props.type}
section={
<Section
number={this.pops.number}
onChange={this.pops.handleChange}
/>
}
/>
Any ideas how I can pass the onChange function down using props? On a similar example the Input change does work but it is loosing focus each time a value is pressed. Already tried assigning keys but that did not work either.
You currently have this as your handleChange method
handleChange = e => {
const { name, value } = e.target.value
this.setState({ [name]: value })
}
You should change it to this.
handleChange = e => {
const { name, value } = e.target;
this.setState({ [name]: value })
}
You seem to be accessing the wrong property in the target because name will always be undefined inside e.target.value and as such, calling setState won't do anything.
Also, you should probably be declaring your function components outside of the class component.
this is because you need to destructure it like this on the next like
const {handleChange} = this.props.handleChange
You can wrap handleChange() in an anonymous function so that it will actively wait for you to make changes to the input. Otherwise it will run on render.
const Section = ({ number, handleChange }) => (
<Fragment>
<div>
<label>Number</label>
<input
type='text'
name='number'
placeholder='123456789'
value={number}
onChange={(e) => handleChange(e)}
/>
</div>
</Fragment>
)

React pass multi state between two components

i found a gist about how to pass state between two components.
Here the jsbin
But how about the multi state?
I want two input fields and show the entered text in other components when i edit it.
i tried edited like this
this.state = {
fieldVal: "" //first input state
otherFieldVal: "" //second
}
and
//input onChange
onUpdate = name => (event) => {
this.setState({ [name]: event.target.value });
};
with no luck.
How can i made it work on multi state for multi input fields ?
Don't need to keep state in both Child and parent. You can write your child component like below, and you can access tow states dynamically by using data-attirb or you can folloe #Isaac 's answer.Keep the state in Child and pass state to Parent or keep the event to Parent from Child.
export class Child extends React.Component {
update = (e) => {
this.props.onUpdate(e.target)
};
render() {
return (
<div>
<h4>Child</h4>
<input
type="text"
placeholder="type here"
onChange={this.update}
data-state = "fieldVal"
value={this.props.fieldVal}
/><br/><br/>
<input
type="text"
placeholder="type here"
onChange={this.update}
data-state = "otherFieldVal"
value={this.props.otherFieldVal}
/>
</div>
)
}
}
export class OtherChild extends React.Component {
render() {
return (
<div>
<h4>OtherChild</h4>
Value in OtherChild Props passedVal1: {this.props.passedVal1} <br/>
Value in OtherChild Props passedVal2: {this.props.passedVal2}
</div>
)
}
}
and in parent :
class App extends Component {
onUpdate = (data) => {
this.setState({
[data.dataset.state]: data.value
})
};
render() {
return (
<div>
<h2>Parent</h2>
Value in Parent Component State fieldVal: {this.state.fieldVal} <br/>
Value in Parent Component State otherFieldVal: {this.state.otherFieldVal}
<br/>
<Child onUpdate={this.onUpdate} fieldVal= {this.state.fieldVal} otherFieldVal ={this.state.otherFieldVal}/>
<br />
<OtherChild passedVal1={this.state.fieldVal} passedVal2={this.state.otherFieldVal}/>
</div>
);
}
}
demo
renderInput = (prop) => {
return (
<Input
onChange={(event) => {
this.setState({ [prop]: event.target.value });
}}
/>
)
}
render() {
<div>
{this.renderInput('name')}
{this.renderInput('age')}
</div>
}
We can set a renderInput method and render different input using parameter to achieve your objective

How to get the values of `textField` in the "Father" component

I set a material-ui/TextField in my user-defined component. The user-defined component is named LabelTextField. I render several LabelTextField in my user-defined component which is named TextList. My question is how to get the values of textField in the TextList component.
A button is next to the TextList component in the View component. I will save all the TextField values when someone clicks the button.
I will post a network request in the TextList component to save the value to the backend.
I am using Redux. Does every material-ui/TextField should dispatch the value in the onChange callback function?
The onChange is at the bottom of this website:
http://www.material-ui.com/#/components/text-field
My central code:
LabelTextField:
textChangeFun = (value) => {
}
render() {
return (
<div>
<div style={{fontSize:0}}>
<div style={inlineStyle}>
<FlatButton disableTouchRipple={true} disabled={true} label={this.props.labelValue} />
</div>
<div style={inlineStyle}>
<TextField
hintText={this.props.textValue}
/>
</div>
</div>
</div>
);
}
TextList:
render(){
return (
<div>
{demoData.map((item,id) =>
<LabelTextField key={id} labelValue={item.label} textValue={item.text} ></LabelTextField>
)}
</div>
)
}
You need to give LabelTextField a handler for the change event.
class LabelTextField extends React.Component {
onChange(e) {
this.props.onChange({ id: this.props.id, value: e.currentTarget.value })
}
render() {
return (
<div>
<div style={{fontSize:0}}>
<div style={inlineStyle}>
<FlatButton disableTouchRipple={true} disabled={true} label={this.props.labelValue} />
</div>
<div style={inlineStyle}>
<TextField
hintText={this.props.textValue}
onChange={this.onChange.bind(this)}
/>
</div>
</div>
</div>
);
}
}
class TextList extends React.Component {
constructor() {
super();
this.state.textFields = {}; // TODO: get initial state from demoData
this.onTextFieldChange = this.onTextFieldChange.bind(this);
}
onTextFieldChange = ({ id, value }) {
const { textFields } = this.state;
textFields[id] = value;
this.setState({ textFields });
}
render(){
return (
<div>
{demoData.map((item,id) =>
<LabelTextField key={id} labelValue={item.label} textValue={item.text} onChange={this.onTextFieldChange} ></LabelTextField>
)}
</div>
)
}
}
This way any time a textField changes, it causes the onTextFieldChange handler to be called and the state of TextList to update.
If you have a more complicated situation, you might consider using redux or even http://redux-form.com/6.5.0/

React - Redux form - state gets set but then resets almost instantly

I have a component in which I'm trying to populate a <Select /> component with some options from my props. When the component mounts, I set the state of jobNumbers to an empty array.
I have two dropdowns in which one's values, depend on the other's selected value. When the value is selected, I run an onChange function to populate the second dropdown. The only problem is when I do this.setState({jobNumbers: [...array elements...]}), the state still shows the jobNumbers array to be empty. The function that actually does the state setting is getCustomerOptions().
Here is my component in it's entirety (it's not TOO terribly long)
import React from 'react';
import SelectInput from '../../components/SelectInput';
import LocationSelector from '../../components/LocationSelector';
import { Field } from 'redux-form/immutable';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
class InputCurrentCustomerLocation extends React.Component {
constructor(props) {
super(props);
this.state = {
jobNumbers: [],
};
this.getCustomerOptions = this.getCustomerOptions.bind(this);
this.onChange = this.onChange.bind(this);
}
componentWillMount() {
if (this.props.active) {
this.props.input.onChange(this.props.active);
}
}
onChange(event) {
if (this.props.input.onChange) {
this.props.input.onChange(event.value); // <-- To be aligned with how redux-form publishes its CHANGE action payload. The event received is an object with 2 keys: "value" and "label"
// Fetch our Locations for this customer
this.props.handleCustomerLocationFetch(event.value);
this.getCustomerOptions(event);
}
}
getCustomerOptions(event) {
let options = [];
if(event) {
this.props.options.forEach((option, index) => {
if(option.value === event.value) {
console.log('props options', this.state);
this.setState({ jobNumbers: this.props.options[index] });
console.log('state options', this.state);
}
})
}
}
render() {
const { meta } = this.props;
return (
<div>
<Select
options={this.props.options} // <-- Receive options from the form
{...this.props}
value={this.props.input.value || ''}
// onBlur={() => this.props.input.onBlur(this.props.input.value)}
onChange={this.onChange.bind(this)}
clearable={false}
/>
{meta.error && <div className="form-error">{meta.error}</div>}
{this.props.activeLocations ? false : (
<div>
<div>
<p> Select a location </p>
<Field
name="locations"
component={props =>
<LocationSelector
{...props}
// active={this.props.activeLocations}
locations={this.props.locations}
/>
}
/>
</div>
<div>
<p> Select a job number</p>
<Field
name="jobNumber"
component={props =>
<Select
options={this.state.jobNumbers}
value={this.props.input.value || ''}
onChange={this.onChange.bind(this)}
clearable={false}
/>
}
/>
</div>
</div>
)}
</div>
);
}
}
export default InputCurrentCustomerLocation;
I'm relatively new to React and redux and I'm not entirely sure why this is happening. Shouldn't the state be populated?
this.setState({ jobNumbers: this.props.options[index] });
is async.
so when you do a console log on the state after setState, the state still won't change.
you should check the value on componentDidUpdate(prevProps, prevState) , and print it there.

Resources