How does one pass a prop as null in react? - javascript

i have a conundrum.
I have text I want toggling in a component.
basically true => tick and false => untick
but i want a 3rd scenario where I don't want any text displayed
if I don't pass the prop to that component, it is automatically assuming true. can I pass propName={null} or something like that?
or will i have to extract this into a function (i'd much rather not)

If you do not provide the prop to the component it will not be present in the object representing props within that component. You could therefore check whether or not the prop is defined:
const Component = (props) => {
if (props.checked === undefined) {
return <Something />;
}
return <SomethingElse someProp={props.checked} />;
};
Then, this will render Something:
<Component />
And these will all render SomethingElse:
<Component checked />
<Component checked={true} />
<Component checked={false} />

You can have a third state null but then you will need to do explicit comparisons i.e a == false and don't evaluate a as it will become false in case of null as well

Related

How do i render ternary operator(if condition) in jsx

This here is the question
Make a component called Gate that accepts 1 prop called "isOpen". When isOpen is true, make the component render "open", and when isOpen is false, make it render "closed". Hint: you can do conditional logic inside JSX with the ternary (question mark, ?) operator, inside single braces, like this: {speed > 80 ? "danger!" : "probably fine"} (which evaluates to "danger!" if speed is over 80, and "probably fine" otherwise).
while this is the code :
import ReactDOM from 'react-dom';
const Gate=({isOpen})=> (
<div>
{ isOpen }
</div>
)
ReactDOM.render(<Gate {isOpen?<h1>hello</h1>:<h1>not hello</h1>} />, document.querySelector('#root'));```
The isOpen value is in the Gate component, so the condition would go in the rendering within that component:
const Gate=({isOpen})=> (
<div>
{ isOpen ? <h1>hello</h1> : <h1>not hello</h1> }
</div>
)
Then when using the component you would pass a value for that prop:
<Gate isOpen={true} />
You can otherwise pass the element to display and put the condition outside the component. For example, taking your original Gate component:
const Gate=({isOpen})=> (
<div>
{ isOpen }
</div>
)
In this case the component isn't expecting a condition as a prop, it's expecting something to render. You can conditionally pass it something to render. But you would need that condition available where you use it. For example, the structure would be like this:
<Gate isOpen={true ? <h1>hello</h1> : <h1>not hello</h1>} />
Clearly this is always true, but in this structure you'd simply replace true with whatever your dynamic condition is.
In either case, isOpen is a prop being passed to the Gate component.
All you have to do is using ternary operator in Gate compoent render open or closed as per the value of isOpen as:
CODESANDBOX LINK
const Gate = ({ isOpen }) => <div>{isOpen ? "open" : "closed"}</div>;
If you want to render in H1 then you can do as:
const Gate2 = ({ isOpen }) => {
return (
<div>
<h1>{isOpen ? "open" : "closed"}</h1>
</div>
);
};

Can I store a component in a variable and push children to it after it has been created?

Let's say that I have this component:
const Test = ({ children, ...rest }) => {
return <>{children}</>
};
export default Test;
I am wondering if it is possible to create a variable that holds the component like this:
const test = <Test></Test>;
And then loop over some data and push children to the test variable on every iteration.
if you don't have the data yet, then all you have to do is conditionally render your component when you do have the data.
{ data ? (<Test>{data.map(...)}</Test>) : <SomeOtherComponent /> /* or null */}
or
{ data ? <>{data.map((x) => <Test>{x}</Test>)}</> : <SomeOtherComponent /> /* or null */}
depending on what you want achieve, i didn't fully understand your question
i.e. if you have the data you need, render the component, rendering the children as you see fit, otherwise render some other component (or null, to render nothing)
Yeap, try that pattern:
const test = (children) => <Test>{children}</Test>;
and usage
<>
{[1,2,3].map(el=>test(el))}
</>
[Edited]
const TestComp = ({children}) => <Test>{children}</Test>;
<>
{[1,2,3].map(el=>(<TestComp>{el}</TestComp>))}
</>

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]} />;
})}
</>
);
}

setState of child component only when it is called

i have a parent component and i have called the child component in its HTML like this.
render() {
<EditBank
deal={dealDetailData && dealDetailData.id}
open={editBankModalStatus}
headerText={"Edit Bank Account"}
getInvestmentOfferingDetailsById = {() =>this.props.getInvestmentOfferingDetailsById({
id: this.props.match.params.id
})}
bankDetail={bankDetails}
toggleEditModal={() => this.handleEditModal("editBankModalStatus", {})}
/>
}
EditBank component is a modal which is only shown when editBankModalStatus is true and it is set to be true on a button click.
Now i want to set the state of EditBank only when button is clicked and whatever bankDetails has been passed to it.
I have tired componentDidMount lifecycle hook but it updated when component is rendered only.
I want to update the state of EditBank component when it is shown on screen only. Any help is appreciated.
Try do this :
render(){
return (
<div>
{editBankModalStatus === true &&
<EditBank
deal={dealDetailData && dealDetailData.id}
open={editBankModalStatus}
headerText={"Edit Bank Account"}
getInvestmentOfferingDetailsById = {() =>this.props.getInvestmentOfferingDetailsById({
id: this.props.match.params.id
})}
bankDetail={bankDetails}
toggleEditModal={() => this.handleEditModal("editBankModalStatus", {})}
/>
}
</div>
);
}
so EditBank will shown only if editBankModalStatus is true.

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