How to use react-select with redux-form? - reactjs

I am trying to integrate react-select using redux form...
Here is my code
import Select from 'react-select'
import StyledSelectField, { StyledMessages } from './style'
const SelectField = props => {
const { input, label, placeholder, options, meta, ...StyledProps } = props
const { onChange, onBlur, onFocus } = props.input
return (
<StyledSelectField {...StyledProps} meta={meta} hasValue={!!input.value}>
<label htmlFor={input.name}>{label}</label>
{placeholder && <div className="placeholder">{placeholder}</div>}
<Select
name={input.name}
value={input.value.value}
onChange={onChange}
onBlur={onBlur}
onFocus={onFocus}
options={options}
{...props}
/>
<StyledMessages>
{meta.touched &&
((meta.error && <span className="error">{meta.error}</span>) ||
(meta.warning && <span className="warning">{meta.warning}</span>))}
</StyledMessages>
</StyledSelectField>
)
}
class TestingCycleForm extends PureComponent {
render() {
const { preMonitoring, handleChange, handleSubmit } = this.props
return (<div>
<Field
label="18%"
name="patientPercentage"
className="form-control"
component={SelectField}
options={Config.get('/PATIENT_PERCENTAGE')}
/>
</div>)
}
}
All things are working but my input field gets cleared on focus out what I am doing wrong here?
Thanks in advance... Any help would be appreciated

You say “focus out” - does that mean it clears on blur? If so, does setting onBlurResetsInput and onCloseResetsInput to false help?
Update: here's the link to the props table from the github readme. You've got to set both onBlurResetsInput and onCloseResetsInput to false at the same time, onBlurResetsInput set to false, by itself, will do nothing.
And also you need to remove the onBlur prop from the select which causes field clear on Blur
<Select
name={input.name}
value={input.value.value}
onChange={onChange}
onBlurResetsInput={false}
onCloseResetsInput={false}
onFocus={onFocus}
options={options}
{...props}
/>

Related

React-Hook-Form Input Element is Empty in Inspect Element but Not in Browser

I am using react-form-hook in a project. I have css styles based on input field value attributes. react-form-hook is setting the values of all the inputs but doesn't show in inspect element niegther my css styles work. I just want to know how react-form-hook set the values on input elements when there is no actual value. Here is the code
import React, { useState } from 'react';
const CustomInput = (props: any) => {
const { label, name, className, type, onChange, register, setValue, value, disabled } = props;
return (
<div className="custom--input--container">
<input
type={type}
name={name}
ref={register}
className={`custom--input ${className}`}
onChange={e => {
onChange();
setValue(name, e.target.value, { shouldValidate: true });
}}
/>
<span className="custom--input--label">{label}</span>
</div>
);
};
export default CustomInput;
Component used here
<CustomInput
label="First Name*"
type="text"
name={SettingsFormFields.FIRST_NAME}
className={classNames({
error: errors[SettingsFormFields.FIRST_NAME],
})}
setValue={setValue}
register={register}
onChange={enableButton}
/>
value is being displaed
No value in inspect element

Automatically Passing Props on Component

I have created an Input component that I have styled with Styled Components. I am now using that Input component with Formik. I would like to be able to automatically set the onChange, onBlur and value props rather than have to set them each and every time (like what happens if I would use the Formik Field component).
That is, right now this is how my component looks when used:
<Input
name="firstName"
onBlur={handleBlur}
onChange={handleChange}
value={values.firstName}
/>
What I would like the component to look like when being used is this:
<Input name="firstName" />
Then, behind the scenes, onBlur would be set to handleBlur, onChange would be set to handleChange and value would be set to values.[name]. That is, to the value of the name prop. So, in this example, it would be set to values.firstName. If the name prop was set to lastName, then the value prop would automatically be set to values.lastName.
Any idea how I can do this?
NOTE: I know that the Field prop from Formik does this, but I want to use my custom Input component instead.
UPDATE
Here is some other code that may be relevant to answering this question.
Input Component
export const Input = props => {
const {
forId,
name,
placeholder,
} = props
const titleCase = startCase(name)
return (
<InputBase {...props}>
<InputSection>
<InputContent
id={forId ? forId : name}
placeholder={placeholder ? placeholder : titleCase}
type="text"
{...props}
/>
</InputSection>
</InputBase>
)
}
InputContent Component
export const InputContent = styled.input`
// STYLES
`
Formik with Form
<Formik
render={props => {
const {
handleBlur,
handleChange,
values,
} = props
return (
<Form>
<Input
name="firstName"
onBlur={handleBlur}
onChange={handleChange}
value={values.firstName}
/>
<Button type="submit">Submit</Button>
</Form>
)
}}
initialValues={{firstName: ''}
validationSchema={validationSchema}
/>
I don't think this is good idea. But what you can do is create HOC and wrap it
// lasyWrapper.js
export function lazyWrapper(Input) {
return LazyWrapper extends React.Component {
render() {
return (
<Input
{...this.props}
name={this.props.name}
onBlur={this.props.handleBlur}
onChange={this.props.handleChange}
value={this.props.values[this.props.name]}
/>
)
}
}
}
// Input.js
export default lazyWrapper(Input)
// use somewhere
<Input
name="firstName"
{...this}
/>
But this is really BAD idea.

How to set state for text box in functional component

I am working on React JS. I have one text-box component and I want to show some default value in it. After that, the user should be allowed to change the value. Now I am unable to change the value. The text box is behaving like read-only. Below is my code
const EditStyleFormComponent = ({
submitting,
invalid,
}) => (
<form className={className} onSubmit={handleSubmit}>
<h2>LSPL (Low Stock Presentation Level)</h2>
<Line />
<InputGroup>
<TextFieldWithValidation name="lsplMan" label="LSPL Manual" input={{ onChnage:'', value: 'Current' }} />
</InputGroup>
</form>
);
Below is my TextFieldWithValidation code.
export const TextFieldWithValidationComponent = ({
meta,
input,
noStyles,
...otherProps
}) => (
<TextField
state={noStyles ? textFieldStates.DEFAULT : getState(meta)}
errorMessage={meta.touched ? meta.error : null}
{...input}
{...otherProps}
/>
);
Below is my TextField code.
const TextField = ({
className,
label,
description,
state,
errorMessage,
isEditable,
spaceAtBottom, // Not used, but we don't want it in otherProps
...otherProps
}) => {
const inputId = _.uniqueId();
return (
<div className={className}>
{label &&
<label htmlFor={inputId}>{label}</label>
}
<div className="input-group" id={isEditable ? 'editable' : 'readonly'}>
<input
id={inputId}
readOnly={!isEditable}
{...otherProps}
/>
{getStatusIcon(state)}
{errorMessage &&
<Error>{errorMessage}</Error>
}
{description &&
<Description>{description}</Description>
}
</div>
</div>
);
};
Can someone help me to fix this issue? Any help would be appreciated. Thanks
You can use State Hook for manage state in functional component.
Example :
const Message = () => {
const [message, setMessage] = useState( '' );
return (
<div>
<input
type="text"
value={message}
placeholder="Enter a message"
onChange={e => setMessage(e.target.value)}
/>
<p>
<strong>{message}</strong>
</p>
</div>
);
};
Yu defined onChange as empty string in EditStyleFormComponent component. So on any change input component just do nothing.
onChange should be some function that will update value.
If you want to use functional components there are two possible solutions:
Lift state up to parent component of EditStyleFormComponent (in case parent is class based component)
Use React Hooks like so (just example!)
const EditStyleFormComponent = ({
submitting,
invalid,
}) => {
const [inputValue, setInputValue] = useState ('Current'); // default value goes here
return <form className={className} onSubmit={handleSubmit}>
<h2>LSPL (Low Stock Presentation Level)</h2>
<Line />
<InputGroup>
<TextFieldWithValidation name="lsplMan" label="LSPL Manual" input={{ onChnage: (e) => { setInputValue(e.target.value); }, value: inputValue }} />
</InputGroup>
</form>
};

Unable to make the Checkbox work with redux-form and react-semantic-ui

I'm trying to use redux-form with react-semantic-ui and is having trouble with the Checkbox component. The Checkbox is not being checked. I've followed the example from the redux-form documentation, but no luck. Here's the Code snippet :
renderCheckBox = ({ input, label }) => {
console.log(input.value);
return (
<Form.Field>
<Checkbox
label={label}
checked={input.value ? true : false}
onChange={input.onChange}
/>
</Form.Field>
);
};
<Field
name="activated"
label="Activate?"
component={this.renderCheckBox}
/>
The output of console.log(input.value) is empty.
Reusable redux form checkbox with semantic ui
import React from 'react';
import { object } from 'prop-types';
import { Field } from 'redux-form/immutable';
import { Checkbox as CheckboxUI } from 'semantic-ui-react';
const Checkbox = ({
input: { value, onChange, ...input },
meta: { touched, error },
...rest
}) => (
<div>
<CheckboxUI
{...input}
{...rest}
defaultChecked={!!value}
onChange={(e, data) => onChange(data.checked)}
type="checkbox"
/>
{touched && error && <span>{error}</span>}
</div>
);
Checkbox.propTypes = {
input: object.isRequired,
meta: object.isRequired
};
Checkbox.defaultProps = {
input: null,
meta: null
};
export default props => <Field {...props} component={Checkbox} />;
How to use?
import Checkbox from './Checkbox';
<form>
...
<Checkbox name="example" />
...
</form>
If you want to know whether the checkbox is checked or not, you have to use
onChange={(e, { checked }) => input.onChange(checked)}
instead of
onChange={input.onChange}
Here's a working example

ReactJS: How to wrap react-select in redux-form field?

I am working on react-select library and facing some issues, I am using redux-form library and importing <Field /> component from it. So that I can submit the values via form to service.
Below mentioned code works fine, when I use default <Select> from react-select. I can able to select the values from the drop down and the value will be selected even on focus out the value will remain. But selected value is not submitting via form due to redux-form that's why I am wrapping <Select /> component and using with <Field name="sample" component={RenderSelectInput} id="sampleEX" options={options} />
import React from 'react';
import Select from 'react-select';
import RenderSelectInput from './RenderSelectInput'; // my customize select box
var options = [{ value: 'one', label: 'One' }, { value: 'two', label: 'Two' }];
class SelectEx extends React.Component {
constructor() {
super();
this.state = { selectValue: 'sample' }
this.updateValue = this.updateValue.bind(this);
}
updateValue(newValue) {
this.setState({ selectValue: newValue })
}
render() {
return (
<div>
<Select name="select1" id="selectBox" value={this.state.selectValue} options={options} onChange={this.updateValue}/>
//This works but value won't submit ...
<Field name="sample" component={RenderSelectInput} id="sampleEX" options={options} />
//For this, selected value vanishes once I come out of component.
</div>
)
}
}
export default SelectEx;
But when I use with my customized select (I am wrapping the to submit the value from form) the <Select> component can be visible in UI even the values also. But unable to select the value from dropdown ..., If I select also it displays in the <Select> box but on focus out it vanishes. Please help me ...
RenderSelectInput component:
import React from 'react';
import {Field, reduxForm} from 'redux-form';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
const RenderSelectInput = ({input, options, name, id}) => (
<div>
<Select {...input} name={name} options={options} id={id} />
</div>
)
export default RenderSelectInput;
When using react-select with redux-form, you'll need to change the default behavior of onChange and onBlur method and call redux-form's onChange and onBlur method respectively.
So, Try this:
const RenderSelectInput = ({input, options, name, id}) => (
<Select
{...input}
id={id}
name={name}
options={options}
value={input.value}
onChange={(value) => input.onChange(value)}
onBlur={(value) => input.onBlur(value)}
/>
)
and use the above component like
<Field component={RenderSelectInput} />
Calling redux-form's onBlur method when focus is removed from the Select field will prevent loss of value.
Here this worked for me,
import React, { Component } from 'react';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
export default class RenderSelectInput extends Component {
onChange(event) {
if (this.props.input.onChange && event != null) {
this.props.input.onChange(event.value);
} else {
this.props.input.onChange(null);
}
}
render() {
const { input, options, name, id, ...custom } = this.props;
return (
<Select
{...input}
{...custom}
id={id}
name={name}
options={options}
value={this.props.input.value || ''}
onBlur={() => this.props.input.onBlur(this.props.input.value)}
onChange={this.onChange.bind(this)}
/>
);
}
}
this was extracted from here: https://ashiknesin.com/blog/use-react-select-within-redux-form/
Use this which works perfectly and it also handles redux form validation.
import React, {Component} from 'react';
import Select from 'react-select';
import {FormGroup} from "reactstrap";
class CustomSelect extends Component {
render() {
const {meta: {touched, error}} = this.props;
const className = ` form-group mb-3 ${touched && error ? 'has-danger' : '' }`;
return (
<FormGroup>
<Select
{...this.props}
value={this.props.input.value}
onChange={(value) => this.props.input.onChange(value)}
onBlur={() => this.props.input.onBlur(this.props.input.value)}
options={this.props.options}
placeholder={this.props.placeholder}
/>
<div className={className}>
<div className="text-help">
{touched ? error : ''}
</div>
</div>
</FormGroup>
);
Use the CustomSelect component in redux form field component as
<Field
name='country_name'
options={this.state.countries}
component={CustomSelect}
placeholder="Select your country"
/>
I had to call the onBlur without any argument. The issue with Hardik's answer was, it was not working in iPad (May be also in other iOS or touch devices. I was unable to check).
The onBlur event is automatically triggered along with the onChange event in iPad. It caused the select value to reset to its initial value. So I had to call onBlur method like this,
onBlur={(value) => input.onBlur()}
const RenderSelectInput = ({input, options, name, id}) => (
<Select
{...input}
id={id}
name={name}
options={options}
value={input.value}
onChange={(value) => input.onChange(value)}
onBlur={(value) => input.onBlur()}
/>
)
and used as,
<Field component={RenderSelectInput} />
Try setting onBlurResetInput property to false.
Something like.
const SelectInput = ({input: { onChange, value }, options, name, id}) => (
<Select
name={name}
value={value}
options={options}
onChange={onChange}
onBlurResetsInput={false}
/>
)
Hope this helps!

Resources