1

My understanding is there are a few ways to pass default values to a prop in React.

However, none of the ones I tried seems to mitigate my issue.

Essentially I'd like to have a default value to prevent undefined values to break the app completely.

i.e React App with useContext() hook

const context = useContext(FarmContext)

// destructuring assigment 
const { fruit = 'foobar' } = context.data.farm[0] // apple


*****
<Compoment fruit={fruit} /> // apple

My problem:

If there is a mistake/typo when chaining the data above on either: cooontext or dattta or farm[55]

The app breaks with cannot read property ________ of undefined

Therefore my destructured fruit = 'foobar' never kick is in place.

// does not work if there's a typo on object chaining
const { fruit = 'foobar' } = context.DA23ta.farm[0] // farm is undefined

*******
<Compoment fruit={fruit} /> // app breaks

Additionally, I've tried passing the default prop value approach:

// does not work if there's a typo
const { fruit } = context.DA23ta.farm[0] // farm is undefined

*******
<Compoment fruit={fruit || 'foobar'} /> // app breaks

I've also tried passing defaultProps as an alternative but I cannot mitigate this issue either.

The only scenario I got this to somewhat work is when I structure the data as:

const fruit = context.data.farm[0].fruuuit // big typo at the end here


// prop will render as 'foobar' bellow
<Compoment fruit={fruit || 'foobar'} /> // foobar

I'd like my code to have a fallback value no matter what happens to the data (typos, values that become undefined overtime).

I'd like that fallback default value to be at the destructuring assignment.

How can I add a preventive defensive strategy when if there's a typo/break anywhere (not just at the very last chained object as I show above) within:

const { fruit = 'foobar' } = contExt.dAta.farMM[0]

How could I still win on the other side and return foobar as the fruit prop and not have my entire app break because of one undefined prop?

Is this possible or doable at all? I'm open to other strategies (if there's any) that I have not shown here.

2 Answers 2

1

Seems like you need something like Ramda's pathOr. Which will return the value by given path, if value exists otherwise return provided default value.

const data = {
  context: {
    data: {
      farm: [
        { fruit: 'apple' },
        { fruit: 'orange' }
      ]
    }
  }
}

const getFruit = R.pathOr('foobar', [ 'context', 'data' , 'farm' , 0, 'fruit' ])
const getFruitWithTypos = R.pathOr('foobar', [ 'contExt', 'dataaaa' , 'form' , 0, 'fruuuuuit' ])

console.log(getFruit(data))
console.log(getFruitWithTypos(data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

Sign up to request clarification or add additional context in comments.

2 Comments

That's very interesting. Thank you for posting that. Though big bummer that this cannot be accomplished natively with JavaScript (?)
@NullisTrue Well, there is "native" approach called optional chaning proposal which you can use right now, for example with babel plugin github.com/tc39/proposal-optional-chaining. But it's only in stage 1 and may not be included into ES standart. Also it requires small changes in syntax from simple . to ?.
0

Optional chaining to the rescue!

Optional chaining is fairly well supported now

const context = useContext(FarmContext)

// destructuring assigment 
const { fruit = 'foobar' } = context?.data?.farm?.[0] ?? {} // apple


<Component fruit={fruit} /> // apple

Also, you can use defaultProps if you can.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.