1

I know that boolean props can be passed to a React component as true or false simply by their presence or absence (as per React JSX documentation and this answer by Artif3x in this StackOverflow question.

So, I might have something like <MyEvent isRecurring /> which passes the isRecurring prop as true, whereas <MyEvent /> would see isRecurring as false (or undefined).

Is it possible to pass a prop with no value (so, it's presence means it is true) when the name of the prop is dynamic (stored in a variable)?

For example, this does not work:

const propToSetToTrue = someCondition ? 'isRecurring' : 'isArchived'

<MyEvent {propToSetToTrue} />  // Syntactically, not allowed

And, to use object spread, I need to set the prop equal to something (naturally, that would be true). This does work, but it's not exactly what I am looking for:

// Assume props already populated at this point
const propToSetToTrue = someCondition ? 'isRecurring' : 'isArchived'
props[propToSetToTrue] = true // This works, but it's not ideal
<MyEvent {...props} />

Use Case

I've gotten a few comments asking why I might need this. Here is a possible use case, in testing:

// sharedExamples/props.js

function textDependsOnProp(Component, propName, testId) {
  it(`sets text to 'FOO' when prop '` + propName + `' is given'`, () => {
    const { queryByTestId } = render(<Component {propName} />) // This does not work
    expect(queryByTestId(testId).textContent).toEqual('FOO')
  })

  it(`sets text to 'BAR' when prop '` + propName + `' is not given'`, () => {
    const { queryByTestId } = render(<Component />)
    expect(queryByTestId(testId).textContent).toEqual('BAR')
  })
}

My tests are in the process of being refactored to be used for many different components, and the actual prop name to focus on may be different for each component, which is why the prop name is dynamic.

So, should I just forget about what I thought was ideal and just explicitly set my prop to true, like so:

const props = {}
props[propName] = true
render(<Component {...props} />)

It just felt like 2 extra lines of code for something I thought could be trivial.

Or is there a way to do it similar to what I've written above?

Alvin S. Lee
  • 4,984
  • 30
  • 34
  • Why do you think your solution is not yet ideal? – Ponleu Mar 11 '19 at 03:20
  • perhaps you can write some adapter. Actually, why you need it? – Alejandro Mar 11 '19 at 03:21
  • 2
    @Leu @Alex - You both have a point. I could easily just explicitly set my prop to true and be done with it. But, I was looking to take advantage of how JSX takes a prop name with no value and defaults it to `true`, in order to throw in a few prop names dynamically, without needing to give them values (like `true`). – Alvin S. Lee Mar 11 '19 at 03:25

2 Answers2

1

The documentation says: "In general, we don’t recommend using this because it can be confused with the ES6 object shorthand {foo} which is short for {foo: foo} rather than {foo: true}. This behavior is just there so that it matches the behavior of HTML." – I do dig the idea but, you're probably better off passing true.

vieko
  • 74
  • 1
  • 5
  • I read that same statement in the documentation too, so I hear what you're saying. But, even though they don't *recommend* passing props with no value, the syntax rules allow for it; so, I just wonder if that means there is a way to do this for dynamically named props too. – Alvin S. Lee Mar 11 '19 at 06:13
0

Check out these examples:

// Example (1)

props['isRecuring'] = true;
<MyEvent {...props}/> // => <MyEvent isRecuring={true}/>

// Example (2)

<MyEvent isRecuring/>

// Example (3)

props['isRecuring'] = undefined;
<MyEvent {...props}/> // => <MyEvent /> mean the isRecuring is not present

Try to display props value in MyEvent

const MyEvent = (props) => (
   <div>props: {JSON.stringify(props)}</div>
)

The result of (1) example is {}, while (2) & (3) display {"isRecuring": true}

Based on the above example, I can say that spreading will ignore the props with value of undefined. Therefore, it not present and will never be passed as props to the component (MyEvent).

I think your solution is the only way to pass boolean props using spread. It the matter of spreading in JS, not the React at all.

Ponleu
  • 1,492
  • 12
  • 27