How to set this input value when 0 is falsey ReactJS - javascript

ReactJS does not like null for a value in <input>.
Warning: value prop on input should not be null. Consider using an
empty string to clear the component or undefined for uncontrolled
components.
Great. My database often returns null because nothing has been set yet.
I am dynamically rendering input fields in a ReactJS app.
value={this.state[row_array[0]] || ''}
The value for this.state[row_array[0]] will sometimes be 0. I want to put 0 in the text field but this evaluates to false ... thus... the empty string '' is put in the text field.
The problem is this.state[row_array[0]] could be anything... 0 is the big problem.
This has some info but nothing helpful for me https://github.com/facebook/react/issues/11417
Any ideas about how I can set that value=0?

Use the conditional operator instead, and check for null:
value={this.state[row_array[0]] === null ? '' : this.state[row_array[0]]}
Setting the value of an input this way tells React that you want to control the component. If it's uncontrolled initially, this will result in a warning - to avoid that warning, make sure to specify that the input is controlled from the start.
Live demo:
const row_array = [0];
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = { 0: null };
this.updateData = this.updateData.bind(this);
}
updateData (event) {
console.log('updated');
this.setState({ [event.target.name]: event.target.value });
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input id={row_array[0]} className="data-input" name={row_array[0]} placeholder="" value={this.state[row_array[0]] === null ? '' : this.state[row_array[0]]} onChange={this.updateData} />
</form>
);
}
}
ReactDOM.render(
<NameForm />,
document.getElementById('root')
);
<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="root"></div>
If it may also be undefined, and not just null, then check that as well:
value={this.state[row_array[0]] === null || this.state[row_array[0]] === undefined ? '' : this.state[row_array[0]]}

When asked for a variable, either with an if or with a ternary operator, it is evaluated to be non-null and non-undefined.
You can try.
class X extends React.Component {
state = {};
render (){
const xdata = this.state[row_array[0]];
const value = xdata ? xdata : '';
return (
<input type="text" value={value} />
)
}
}

Related

Component doesn't Update on Props Change

This component doesn't update even tho props change.
prop row is an object.
console.log("row", row") does work. and get correct data also console.log("Data", data)
import React, {useState, useEffect} from "react";
const Form = ({row}) => {
const [data, setData] = useState(row);
console.log("row", row); //consoleLog1
useEffect(() => {
setData(row);
}, [row]);
return (
<>
{Object.getOwnPropertyNames(data).map((head) => {
console.log("Data", data);//consoleLog2
return <input type="text" name={head} defaultValue={data[head] == null ? "" : data[head]} />;
})}
</>
);
};
export default Form;
Update
changing return to <input value={data["ID"}> . and it does update .
is there any way to create a form using looping object's properties?
The defaultValue prop is used for uncontrolled components. It sets the starting value, and then it's out of your hands. All changes will be handled internally by input. So when you rerender and pass in a new defaultValue, that value is ignored.
If you need to change the value externally, then you either need to unmount and remount the components, which can be done by giving them a key which changes:
<input key={data[head].someUniqueIdThatChanged}
Or you need to use the input in a controlled manner, which means using the value prop instead.
value={data[head] == null ? "" : data[head]}
For more information on controlled vs uncontrolled components in react, see these pages:
https://reactjs.org/docs/forms.html#controlled-components
https://reactjs.org/docs/uncontrolled-components.html
P.S, copying props into state is almost always a bad idea. Just use the prop directly:
const Form = ({row}) => {
return (
<>
{Object.getOwnPropertyNames(row).map((head) => {
return <input type="text" name={head} defaultValue={row[head] == null ? "" : row[head]} />;
})}
</>
);
}

How to update state on disabled field in react

I am trying to showing default value and want to disable it field . Values is showing successfully but did not update it state . Could someone please help me how to update state on disable field . I really tried hard but didn't find any solution .
Thanks
Code
componentWillReceiveProps(nextProps) {
const { projectData } = nextProps;
this.setState({
project: projectData,
});
}
componentDidMount() {
const { stan_rate_Per_sqft, category_charges, project } = this.state;
console.log("##### data", stan_rate_Per_sqft, category_charges);
if (
project &&
project.category_charges_apply &&
project.category_charges_apply === "yes"
) {
this.setState({
rate_Per_sqft: stan_rate_Per_sqft * parseInt(1 + category_charges),
});
}
}
In Render Method
<td>
<input
type="text"
className="inputStyle"
name="rate_Per_sqft"
value={rate_Per_sqft}
disabled={true}
placeholder="Category Charges"
/>
</td>
Your component is always disabled since it's hardcoded to true. If you want it to have a dynamic state you'll need to add key to your class state.
...
constructor(props) {
super(props);
this.state = { isDisabled: true }
}
...
Now, in your input field, you may use this state...
<input ... disabled={this.state.isDisabled} />
When isDisabled is set to false (using setState), the field will be enabled again and vice versa.
The disabled attribute on an <input> element works by passing in a boolean value. A truthy value will disable it, a falsy value will enable it.
With that in mind we could use the negated value of rate_Per_sqft to enable the input element. Perhaps something like this:
class App extends React.Component {
state = {
rate_Per_sqft: null
}
componentDidMount() {
// Simulate asynchronous operation
setTimeout(() => {
this.setState({ rate_Per_sqft: 550 })
}, 1500)
}
render() {
const { rate_Per_sqft } = this.state
return(
<div>
{!rate_Per_sqft && <span>Calculating charges..</span>}
<input
type="text"
name="rate_Per_sqft"
value={rate_Per_sqft}
disabled={!rate_Per_sqft}
placeholder="Category Charges"
/>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
<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="root"></div>
Note: I wasn't sure if you wanted the form disabled or enabled by default. So, I disabled it. Also, I simplified the code to keep the example short and simple.

React a component is changing an uncontrolled input of type checkbox to be controlled

react gives me a warning: "A component is changing an uncontrolled input of type checkbox to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa)."
However my checbox is change via the state property. Am I missing something obvious?
import React from 'react';
// Components
import Checkbox from './checkbox';
import HelpBubble from './helpBubble';
export default class CheckboxField extends React.Component {
constructor(props) {
super(props);
this.state = {value: props.value};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
componentWillReceiveProps(nextProps) {
if (nextProps.value !== this.props.value) {
this.setState({value: nextProps.value});
}
}
render() {
const {label, meta = {}, help, disabled, required, onChange} = this.props;
return (
<label className="checkbox-wrap form-field">
<Checkbox
disabled={disabled}
type="checkbox"
onChange={(event) => {
onChange(event, !this.state.value);
}}
checked={this.state.value}/>
{label && (
<div className="checkbox-label">
{label}
{required && <div className="form-field__required"/>}
</div>
)}
{help && <HelpBubble help={help}/>}
{meta.error && meta.touched && (
<div className="input-error">{meta.error}</div>
)}
</label>
);
}}
Parent component:
handleChangeParams(key, value)
}
/>
Handle change params changes the value in model and calls server. Depending on server result, the value can change.
Thanks in advance.
If your state is initialized with props.value being null React will consider your Checkbox component to be uncontrolled.
Try setting your initial state so that value is never null.
this.state = { value: props.value || "" };
If you are using a checkbox react won't like a string either so instead try
this.state = { checkboxValue: props.checkboxValue || false };
Something worth noting about the above code snippet. When you set a state in the constructor from props, it is always best to set the state to a "controlled" value i.e. a tangible value such as an int, float, string, array, map, etc. The error you are getting is the result of props.value being set to null
So, Consider setting your constructor state like this:
this.state = {
value: props.value ? props.value : 'empty'
}
What is happening here is it is checking if props.value has a value, if it does it sets the state to props.value, if props.value is null, it sets the state to the string: `'empty'
Another simple way to do this would be to !! your props.checkboxValue value. That way even if it's undefined, !!props.checkboxValue will resolve to false.
this.state = { checkboxValue: !!props.checkboxValue };
In my case, I was using a prop from my redux store to set whether the checkbox was checked, simply defaulting the property to false worked for me.
e.g.
const MyComponent = ({
somePropFromRedux
}) => {
return <thatThridPartyCheckboxComponent checked={somePropFromRedux} />
}
becomes (only change is adding = false on Line 2)
const MyComponent = ({
somePropFromRedux = false
}) => {
return <thatThridPartyCheckboxComponent checked={somePropFromRedux} />
}
do not use e.target.checked in the inputbox onChange eventHandler method.
Correct way:
const [isChecked, setCheck] = useState(false);
const handler = (e) => {
setCheck(!isChecked);
};
<input
type="checkbox"
checked={isChecked}
onChange={handler}
/>

React - changing an uncontrolled input

I have a simple react component with the form which I believe to have one controlled input:
import React from 'react';
export default class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={this.state.name} onChange={this.onFieldChange('name').bind(this)}/>
</form>
)
}
onFieldChange(fieldName) {
return function (event) {
this.setState({[fieldName]: event.target.value});
}
}
}
export default MyForm;
When I run my application I get the following warning:
Warning: MyForm is changing an uncontrolled input of type text to be
controlled. Input elements should not switch from uncontrolled to
controlled (or vice versa). Decide between using a controlled or
uncontrolled input element for the lifetime of the component
I believe my input is controlled since it has a value. I am wondering what am I doing wrong?
I am using React 15.1.0
I believe my input is controlled since it has a value.
For an input to be controlled, its value must correspond to that of a state variable.
That condition is not initially met in your example because this.state.name is not initially set. Therefore, the input is initially uncontrolled. Once the onChange handler is triggered for the first time, this.state.name gets set. At that point, the above condition is satisfied and the input is considered to be controlled. This transition from uncontrolled to controlled produces the error seen above.
By initializing this.state.name in the constructor:
e.g.
this.state = { name: '' };
the input will be controlled from the start, fixing the issue. See React Controlled Components for more examples.
Unrelated to this error, you should only have one default export. Your code above has two.
When you first render your component, this.state.name isn't set, so it evaluates to undefined or null, and you end up passing value={undefined} or value={null}to your input.
When ReactDOM checks to see if a field is controlled, it checks to see if value != null (note that it's !=, not !==), and since undefined == null in JavaScript, it decides that it's uncontrolled.
So, when onFieldChange() is called, this.state.name is set to a string value, your input goes from being uncontrolled to being controlled.
If you do this.state = {name: ''} in your constructor, because '' != null, your input will have a value the whole time, and that message will go away.
Another approach it could be setting the default value inside your input, like this:
<input name="name" type="text" value={this.state.name || ''} onChange={this.onFieldChange('name').bind(this)}/>
I know others have answered this already. But a very important factor here that may help other people experiencing similar issue:
You must have an onChange handler added in your input field (e.g. textField, checkbox, radio, etc). Always handle activity through the onChange handler.
Example:
<input ... onChange={ this.myChangeHandler} ... />
When you are working with checkbox you may need to handle its checked state with !!.
Example:
<input type="checkbox" checked={!!this.state.someValue} onChange={.....} >
Reference: https://github.com/facebook/react/issues/6779#issuecomment-326314716
Simple solution to resolve this problem is to set an empty value by default :
<input name='myInput' value={this.state.myInput || ''} onChange={this.handleChange} />
One potential downside with setting the field value to "" (empty string) in the constructor is if the field is an optional field and is left unedited. Unless you do some massaging before posting your form, the field will be persisted to your data storage as an empty string instead of NULL.
This alternative will avoid empty strings:
constructor(props) {
super(props);
this.state = {
name: null
}
}
...
<input name="name" type="text" value={this.state.name || ''}/>
I had the same problem.
the problem was when i kept the state info blank
const [name, setName] = useState()
I fixed it by adding empty string like this
const [name, setName] = useState('')
In my case, I was missing something really trivial.
<input value={state.myObject.inputValue} />
My state was the following when I was getting the warning:
state = {
myObject: undefined
}
By alternating my state to reference the input of my value, my issue was solved:
state = {
myObject: {
inputValue: ''
}
}
When you use onChange={this.onFieldChange('name').bind(this)} in your input you must declare your state empty string as a value of property field.
incorrect way:
this.state ={
fields: {},
errors: {},
disabled : false
}
correct way:
this.state ={
fields: {
name:'',
email: '',
message: ''
},
errors: {},
disabled : false
}
If the props on your component was passed as a state, put a default value for your input tags
<input type="text" placeholder={object.property} value={object.property ? object.property : ""}>
Set a value to 'name' property in initial state.
this.state={ name:''};
An update for this. For React Hooks use const [name, setName] = useState(" ")
Simply create a fallback to '' if the this.state.name is null.
<input name="name" type="text" value={this.state.name || ''} onChange={this.onFieldChange('name').bind(this)}/>
This also works with the useState variables.
I believe my input is controlled since it has a value.
Now you can do this two ways the best way is to have a state key to each input with 1 onChange handler. If you have checkboxes you will need to write a separate onChange handler.
With a Class component you would want to write it like this 👇
import React from 'react';
export default class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = {
myFormFields: {
name: '',
dob: '',
phone: ''
}
}
this.onFormFieldChange = this.onFormFieldChange.bind(this)
}
// Always have your functions before your render to keep state batches in sync.
onFormFieldChange(e) {
// No need to return this function can be void
this.setState({
myFormFields: {
...this.state.myFormFields,
[e.target.name]: e.target.value
}
})
}
render() {
// Beauty of classes we can destruct our state making it easier to place
const { myFormFields } = this.state
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={myFormFields.name} onChange={this.onFormFieldChange}/>
<input name="dob" type="date" value={myFormFields.dob} onChange={this.onFormFieldChange}/>
<input name="phone" type="number" value={myFormFields.phone} onChange={this.onFormFieldChange}/>
</form>
)
}
}
export default MyForm;
Hope that helps for a class but the most performative and what the newest thing the devs are pushing everyone to use is Functional Components. This is what you would want to steer to as class components don't intertwine well with the latest libraries as they all use custom hooks now.
To write as a Functional Component
import React, { useState } from 'react';
const MyForm = (props) => {
// Create form initial state
const [myFormFields, setFormFields] = useState({
name: '',
dob: '',
phone: ''
})
// Always have your functions before your return to keep state batches in sync.
const onFormFieldChange = (e) => {
// No need to return this function can be void
setFormFields({
...myFormFields,
[e.target.name]: e.target.value
})
}
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={myFormFields.name} onChange={onFormFieldChange}/>
<input name="dob" type="date" value={myFormFields.dob} onChange={onFormFieldChange}/>
<input name="phone" type="number" value={myFormFields.phone} onChange={onFormFieldChange}/>
</form>
)
}
export default MyForm;
Hope this helps! 😎
In short, if you are using class component you have to initialize the input using state, like this:
this.state = { the_name_attribute_of_the_input: "initial_value_or_empty_value" };
and you have to do this for all of your inputs you'd like to change their values in code.
In the case of using functional components, you will be using hooks to manage the input value, and you have to put initial value for each input you'd like to manipulate later like this:
const [name, setName] = React.useState({name: 'initialValue'});
If you'd like to have no initial value, you can put an empty string.
In my case component was rerendering and throwing A component is changing an uncontrolled input of type checkbox to be controlled error. It turned out that this behaviour was a result of not keeping true or false for checkbox checked state (sometimes I got undefined). Here what my faulty component looked like:
import * as React from 'react';
import { WrappedFieldProps } from 'redux-form/lib/Field';
type Option = {
value: string;
label: string;
};
type CheckboxGroupProps = {
name: string;
options: Option[];
} & WrappedFieldProps;
const CheckboxGroup: React.FC<CheckboxGroupProps> = (props) => {
const {
name,
input,
options,
} = props;
const [value, setValue] = React.useState<string>();
const [checked, setChecked] = React.useState<{ [name: string]: boolean }>(
() => options.reduce((accu, option) => {
accu[option.value] = false;
return accu;
}, {}),
);
React.useEffect(() => {
input.onChange(value);
if (value) {
setChecked({
[value]: true, // that setChecked argument is wrong, causes error
});
} else {
setChecked(() => options.reduce((accu, option) => {
accu[option.value] = false;
return accu;
}, {}));
}
}, [value]);
return (
<>
{options.map(({ value, label }, index) => {
return (
<LabeledContainer
key={`${value}${index}`}
>
<Checkbox
name={`${name}[${index}]`}
checked={checked[value]}
value={value}
onChange={(event) => {
if (event.target.checked) {
setValue(value);
} else {
setValue(undefined);
}
return true;
}}
/>
{label}
</LabeledContainer>
);
})}
</>
);
};
To fix that problem I changed useEffect to this
React.useEffect(() => {
input.onChange(value);
setChecked(() => options.reduce((accu, option) => {
accu[option.value] = option.value === value;
return accu;
}, {}));
}, [value]);
That made all checkboxes keep their state as true or false without falling into undefined which switches control from React to developer and vice versa.
For people using Formik, you need to add a default value for the specific field name to the form's initialValues.
This generally happens only when you are not controlling the value of the filed when the application started and after some event or some function fired or the state changed, you are now trying to control the value in input field.
This transition of not having control over the input and then having control over it is what causes the issue to happen in the first place.
The best way to avoid this is by declaring some value for the input in the constructor of the component.
So that the input element has value from the start of the application.
Please try this code
import React from "react";
class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = { name: "" };
this.onFieldChange = this.onFieldChange.bind(this);
}
onFieldChange(e) {
this.setState({[e.target.name]: e.target.value});
}
render() {
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={this.state.name} onChange={this.onFieldChange} />
</form>
);
}
}
export default MyForm;
In my case there was spell mistake while setting the state which was causing defined value to be undefined.
This is my default state with value
const [email, setEmail] = useState(true);
my mistake was-
setEmail(res?.data?.notificationSetting.is_email_notificatio);
and the solution is -
setEmail(res?.data?.notificationSetting.is_email_notification);
last char was missing
I had the same issue with type='radio'
<input type='radio' checked={item.radio} ... />
the reason was that item.radio is not always true or false, but rather true or undefined, for example. Make sure it’s always boolean, and the problem will go away.
<input type='radio' checked={!!item.radio} ... />
source
For dynamically setting state properties for form inputs and keeping them controlled you could do something like this:
const inputs = [
{ name: 'email', type: 'email', placeholder: "Enter your email"},
{ name: 'password', type: 'password', placeholder: "Enter your password"},
{ name: 'passwordConfirm', type: 'password', placeholder: "Confirm your password"},
]
class Form extends Component {
constructor(props){
super(props)
this.state = {} // Notice no explicit state is set in the constructor
}
handleChange = (e) => {
const { name, value } = e.target;
this.setState({
[name]: value
}
}
handleSubmit = (e) => {
// do something
}
render() {
<form onSubmit={(e) => handleSubmit(e)}>
{ inputs.length ?
inputs.map(input => {
const { name, placeholder, type } = input;
const value = this.state[name] || ''; // Does it exist? If so use it, if not use an empty string
return <input key={name} type={type} name={name} placeholder={placeholder} value={value} onChange={this.handleChange}/>
}) :
null
}
<button type="submit" onClick={(e) => e.preventDefault }>Submit</button>
</form>
}
}

Dynamically add React attributes [duplicate]

Is there a way to only add attributes to a React component if a certain condition is met?
I'm supposed to add required and readOnly attributes to form elements based on an Ajax call after render, but I can't see how to solve this since readOnly="false" is not the same as omitting the attribute completely.
The example below should explain what I want, but it doesn't work.
(Parse Error: Unexpected identifier)
function MyInput({isRequired}) {
return <input classname="foo" {isRequired ? "required" : ""} />
}
Apparently, for certain attributes, React is intelligent enough to omit the attribute if the value you pass to it is not truthy. For example:
const InputComponent = function() {
const required = true;
const disabled = false;
return (
<input type="text" disabled={disabled} required={required} />
);
}
will result in:
<input type="text" required>
Update: if anyone is curious as to how/why this happens, you can find details in ReactDOM's source code, specifically at lines 30 and 167 of the DOMProperty.js file.
juandemarco's answer is usually correct, but here is another option.
Build an object how you like:
var inputProps = {
value: 'foo',
onChange: this.handleChange
};
if (condition) {
inputProps.disabled = true;
}
Render with spread, optionally passing other props also.
<input
value="this is overridden by inputProps"
{...inputProps}
onChange={overridesInputProps}
/>
Here is an example of using Bootstrap's Button via React-Bootstrap (version 0.32.4):
var condition = true;
return (
<Button {...(condition ? {bsStyle: 'success'} : {})} />
);
Depending on the condition, either {bsStyle: 'success'} or {} will be returned. The spread operator will then spread the properties of the returned object to Button component. In the falsy case, since no properties exist on the returned object, nothing will be passed to the component.
An alternative way based on Andy Polhill's comment:
var condition = true;
return (
<Button bsStyle={condition ? 'success' : undefined} />
);
The only small difference is that in the second example the inner component <Button/>'s props object will have a key bsStyle with a value of undefined.
Here is an alternative.
var condition = true;
var props = {
value: 'foo',
...(condition && { disabled: true })
};
var component = <div {...props} />;
Or its inline version
var condition = true;
var component = (
<div value="foo" {...(condition && { disabled: true })} />
);
Here's a way I do it.
With a conditional:
<Label
{...{
text: label,
type,
...(tooltip && { tooltip }),
isRequired: required
}}
/>
I still prefer using the regular way of passing props down, because it is more readable (in my opinion) in the case of not have any conditionals.
Without a conditional:
<Label text={label} type={type} tooltip={tooltip} isRequired={required} />
Let’s say we want to add a custom property (using aria-* or data-*) if a condition is true:
{...this.props.isTrue && {'aria-name' : 'something here'}}
Let’s say we want to add a style property if a condition is true:
{...this.props.isTrue && {style : {color: 'red'}}}
You can use the same shortcut, which is used to add/remove (parts of) components ({isVisible && <SomeComponent />}).
class MyComponent extends React.Component {
render() {
return (
<div someAttribute={someCondition && someValue} />
);
}
}
If you use ECMAScript 6, you can simply write like this.
// First, create a wrap object.
const wrap = {
[variableName]: true
}
// Then, use it
<SomeComponent {...{wrap}} />
Using undefined works for most properties:
const name = "someName";
return (
<input name={name ? name : undefined} />
);
This should work, since your state will change after the Ajax call, and the parent component will re-render.
render : function () {
var item;
if (this.state.isRequired) {
item = <MyOwnInput attribute={'whatever'} />
} else {
item = <MyOwnInput />
}
return (
<div>
{item}
</div>
);
}
For some boolean attributes listed by React [1]:
<input disabled={disabled} />
// renders either `<input>` or `<input disabled>`
For other attributes:
<div aria-selected= {selected ? "" : undefined} />
// renders either `<div aria-selected></div>` or `<div></div>`
[1] The list of boolean attributes: https://github.com/facebook/react/blob/3f9480f0f5ceb5a32a3751066f0b8e9eae5f1b10/packages/react-dom/src/shared/DOMProperty.js#L318-L345
For example using property styles for custom container
const DriverSelector = props => {
const Container = props.container;
const otherProps = {
...( props.containerStyles && { style: props.containerStyles } )
};
return (
<Container {...otherProps} >
In React you can conditionally render Components, but also their attributes, like props, className, id, and more.
In React it's very good practice to use the ternary operator which can help you conditionally render Components.
An example also shows how to conditionally render Component and its style attribute.
Here is a simple example:
class App extends React.Component {
state = {
isTrue: true
};
render() {
return (
<div>
{this.state.isTrue ? (
<button style={{ color: this.state.isTrue ? "red" : "blue" }}>
I am rendered if TRUE
</button>
) : (
<button>I am rendered if FALSE</button>
)}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
From my point of view the best way to manage multiple conditional props is the props object approach from #brigand. But it can be improved in order to avoid adding one if block for each conditional prop.
The ifVal helper
rename it as you like (iv, condVal, cv, _, ...)
You can define a helper function to return a value, or another, if a condition is met:
// components-helpers.js
export const ifVal = (cond, trueValue=true, falseValue=null) => {
return cond ? trueValue : falseValue
}
If cond is true (or truthy), the trueValue is returned - or true.
If cond is false (or falsy), the falseValue is returned - or null.
These defaults (true and null) are, usually the right values to allow a prop to be passed or not to a React component. You can think to this function as an "improved React ternary operator". Please improve it if you need more control over the returned values.
Let's use it with many props.
Build the (complex) props object
// your-code.js
import { ifVal } from './components-helpers.js'
// BE SURE to replace all true/false with a real condition in you code
// this is just an example
const inputProps = {
value: 'foo',
enabled: ifVal(true), // true
noProp: ifVal(false), // null - ignored by React
aProp: ifVal(true, 'my value'), // 'my value'
bProp: ifVal(false, 'the true text', 'the false text') // 'my false value',
onAction: ifVal(isGuest, handleGuest, handleUser) // it depends on isGuest value
};
<MyComponent {...inputProps} />
This approach is something similar to the popular way to conditionally manage classes using the classnames utility, but adapted to props.
Why you should use this approach
You'll have a clean and readable syntax, even with many conditional props: every new prop just add a line of code inside the object declaration.
In this way you replace the syntax noise of repeated operators (..., &&, ? :, ...), that can be very annoying when you have many props, with a plain function call.
Our top priority, as developers, is to write the most obvious code that solve a problem.
Too many times we solve problems for our ego, adding complexity where it's not required.
Our code should be straightforward, for us today, for us tomorrow and for our mates.
just because we can do something doesn't mean we should
I hope this late reply will help.
<input checked={true} type="checkbox" />
In react functional component you can try something like this to omit unnecessary tag property.
<div className="something" ref={someCondition ? dummyRef : null} />
This works for me if I need to omit tags like ref, class, etc. But I don't know if that's work for every tag property
<Button {...(isWeb3Enabled ? {} : { isExternal: true })}>
Metamask
</Button>
Given a local variable isRequired You can do the following in your render method (if using a class) or return statement (if using a function component):
<MyComponent required={isRequired ? 'true' : undefined} />
In this case, the attribute will not be added if isRequired is undefined, false, or null (which is different from adding the attribute but setting it to 'false'.) Also note that I am using strings instead of booleans in order to avoid a warning message from react (Boolean value received on non-boolean attribute).
Considering the post JSX In Depth, you can solve your problem this way:
if (isRequired) {
return (
<MyOwnInput name="test" required='required' />
);
}
return (
<MyOwnInput name="test" />
);
I think this may be useful for those who would like attribute's value to be a function:
import { RNCamera } from 'react-native-camera';
[...]
export default class MyView extends React.Component {
_myFunction = (myObject) => {
console.log(myObject.type); //
}
render() {
var scannerProps = Platform.OS === 'ios' ?
{
onBarCodeRead : this._myFunction
}
:
{
// here you can add attribute(s) for other platforms
}
return (
// it is just a part of code for MyView's layout
<RNCamera
ref={ref => { this.camera = ref; }}
style={{ flex: 1, justifyContent: 'flex-end', alignItems: 'center', }}
type={RNCamera.Constants.Type.back}
flashMode={RNCamera.Constants.FlashMode.on}
{...scannerProps}
/>
);
}
}
in an easy way
const InputText= ({required = false , disabled = false, ...props}) =>
(<input type="text" disabled={disabled} required={required} {...props} />);
and use it just like this
<InputText required disabled/>
In addition, you can make other value to Boolean
const MyComponent = function() {
const Required = "yes";
return (
<input
required={Required === "yes"}
type="text"
key={qs.Name}
name="DefaultValue"
label={qs.QuestionTitle}
onChange={(event) => handleInputChange(index, event)}
placeholder={qs.QuestionTitle}
/>
);
}
If it is for a limited number of properties this will do
function MyInput({isRequired}) {
if (isRequired) {
return <input classname="foo" isRequired={isRequired} />
}
return <input classname="foo" />
}
If you have a large number of properties, it will be difficult to write if else conditions for every property and return accordingly. For that, you can push those properties in an object and use the spread operator in the returned element.
function MyInput({ prop1, prop2, ...propN }) {
const props = {};
if (prop1) props.prop1 = prop1;
.
.
.
if (propN) props.propN = propN;
return <input classname="foo" {...props} />
}
You must set as undefined the value for when you do not need the attribute
Example:
<a data-tooltip={sidebarCollapsed?'Show details':undefined}></a>
In React, we pass values to component from parent to child as Props. If the value is false, it will not pass it as props. Also in some situation we can use ternary (conditional operator) also.

Categories