如何检查深层嵌套的道具

时间:2019-02-19 10:58:53

标签: javascript arrays reactjs

我经常发现自己必须先构建长链,然后才能映射到数组上以检查是否已定义:

this.props.photos &&
this.props.photos.activePhotos &&
this.props.photos.activePhotos.map(...

如果未定义this.props.photos &&this.props.photos.activePhotos.length &&,而photosactivePhotos未定义,我的整个应用程序将崩溃。

有没有一种方法可以检查这些道具而不必检查我的最终物品的每个父对象/数组?

6 个答案:

答案 0 :(得分:7)

另一种选择是在解构道具时使用默认值:

  const { photos = {} } = this.props
  const { activePhotos = [] } = photos
  activePhotos.map(/*   */)

在这种情况下,如果未定义photos,它将被一个空对象代替。尝试从中取出activePhotos会得到一个空数组,无论如何都可以在其上进行映射。

答案 1 :(得分:4)

我猜您指的是可选链接,这是TC39的第1阶段

https://github.com/tc39/proposal-optional-chaining

答案 2 :(得分:1)

根据嵌套的级别,我看到了两种可能的方法。

#1。如果您有许多嵌套的道具等级:

您可以使用lodash.get

只有在activePhotos存在的情况下,这里是如何渲染它们的方法:

// Please note how do we pass default `[]` as third parameter
// in order to not break the `.map` function
_.get(this.props, 'photos.activePhotos', []).map(...)

如果您只想检查深度嵌套的专家,则可以使用lodash.has方法:

// Will return `true` / `false`
_.has(this.props, 'photos.activePhotos')

#2。如果嵌套级别不再是2-3个级别:

只需使用本机ES6解构分配+默认值功能。

const { photos = {} } = this.props
const { activePhotos = [] } = photos

// Now you can safely map over the `activePhotos`
activePhotos.map(...)

答案 3 :(得分:0)

  

有没有一种方法可以检查这些道具而不必检查每个   最终项目的父对象/数组?

通常,不会。

目前尚不清楚为什么在问题代码处检查了.length的电位。

如果目标是减少代码长度,则可以使用JSON.stringify()RegExp

if (/"activePhotos":\[.*\]/.test(JSON.stringify(this.props))) // do stuff

或者如果首选方法是使用AND运算符

/"activePhotos":\[.*\]/.test(JSON.stringify(this.props)) && // do stuff

答案 4 :(得分:0)

undefsafe 是一个足够好的库可供使用。还有很多其他可用的库。

使用方法的简单示例

var object = {
  a: {
    b: {
      c: 1,
      d: [1,2,3],
      e: 'remy'
    }
  }
};

console.log(undefsafe(object, 'a.b.e')); // "remy"
console.log(undefsafe(object, 'a.b.not.found')); // undefined

答案 5 :(得分:-1)

这是具有默认值返回的功能性方法,用于可选链接。该方法使用Maybe单子和Proxy

wrap()函数用于包装可以安全访问任何属性的对象。在内部,wrap在对象周围创建代理,并使用Maybe包装器管理缺失值。在链的最后,您可以通过将getOrElse(default)与默认值链接来解开该值,默认值将在属性访问失败时返回:

class Maybe {
  constructor(value) {
    this.__value = value;
  }
  static of(value){
    if (value instanceof Maybe) return value;
    return new Maybe(value);
  }
  getOrElse(elseVal) {
    return this.isNothing() ? elseVal : this.__value;
  }
  isNothing() {
    return this.__value === null || this.__value === undefined;
  }
  map(fn) {  
    return this.isNothing()
      ? Maybe.of(null)
      : Maybe.of(fn(this.__value));
  }
}

function wrap(obj) {
  function fix(object, property) {
    const value = object[property];
    return typeof value === 'function' ? value.bind(object) : value;
  }
  return new Proxy(Maybe.of(obj), {
    get: function(target, property) {
      if (property in target) {
          return fix(target, property);
      } else {
        return wrap(target.map(val => fix(val, property)));
      }
    }
  });
}

const obj = { a: 1, b: { c: [4, 1, 2] }, c: () => 'yes' };

console.log(wrap(obj).a.getOrElse(null)) // returns 1
console.log(wrap(obj).a.b.c.d.e.f.getOrElse(null)) // returns null
console.log(wrap(obj).b.c.getOrElse([])) // returns [4, 1, 2]
console.log(wrap(obj).b.c[0].getOrElse(null)) // returns 4
console.log(wrap(obj).b.c[100].getOrElse(-1)) // out-of-bounds index: returns -1
console.log(wrap(obj).c.getOrElse(() => 'no')()) // returns 'yes'
console.log(wrap(obj).d.getOrElse(() => 'no')()) // returns 'no'

请参阅this blog postthis link,以获取有关Maybe monad和代理使用的更多信息。