检查值是否是有效的 React Child

时间:2021-05-06 16:29:05

标签: javascript reactjs

我有一个简单的 React 组件来包装它的 children

function Wrapper(props) {
    return <div>{props.children}</div>;
}

如果我传递了一个无效的子组件,这个组件会抛出一个错误:

const plain_object = {};

// This throws an error
ReactDOM.render(<Wrapper>{plain_object}</Wrapper>, container);

我想要的是检查我传入的孩子是否会无错误地渲染,任何有效的“可渲染”值。例如:

function SafeWrapper(props) {
    // Note, this function doesn't exist, but I want it to
    if (!isValidChildren(props.children)) {
        return null;
    }

    return <div>{props.children}</div>;
}

const plain_object = {};

// This will no longer throw
ReactDOM.render(<SafeWrapper>{plain_object}</SafeWrapper>, container);

我知道 React 有 React.isValidElement,但这不会检查原始代码或任何其他可以正常渲染的项目:

// The following calls all return `false` despite them
// not throwing errors when you try and pass them in the `children` prop
// Note that not all of these will render (e.g. the falsy values are skipped)
// but they still don't throw.
React.isValidElement('');
React.isValidElement('Hello');
React.isValidElement(0);
React.isValidElement(1);
React.isValidElement(null);
React.isValidElement(undefined);
React.isValidElement([1]);
React.isValidElement([<div />]);

是否有我在示例中提到的 isValidChildren 函数?如果没有,写一个会是什么样子?

/**
 * Returns `true` if `children` can be passed without throwing. `false` if otherwise.
 */
function isValidChildren(children) {
    // ?
}

2 个答案:

答案 0 :(得分:1)

你可以这样做:

const isRenderable = (node) => {
  let renderable;
  switch (typeof node) {
    case "string":
    case "number":
      renderable = true;
      break;
    default:
      if (Array.isArray(node) && node.length) {
        renderable = node.reduce((acc, e) => acc && isRenderable(e), true);
        break;
      }
      renderable = React.isValidElement(node);
      break;
  }
  return renderable;
};

答案 1 :(得分:0)

它没有直接回答您关于实现要检查的函数的问题,但您可以使用带有内部空包装器的 ErrorBoundary 来处理不可渲染内容的情况:

class ErrorBoundary extends React.Component {
  state = { error: null, errorInfo: null }

  static getDerivedStateFromError(error, errorInfo) {
    return { error, errorInfo }
  }

  render() {
    if (this.state.error) {
      return <span>something went wrong</span>
    }
    return this.props.children
  }
}

// needed because the error boundary catches errors
// in *nested* components, whereas if it tried
// to render the children directly, it can't catch
// errors in its own `render`
const Inner = ({ children }) => children

const SafeWrapper = ({ children }) => (
  <ErrorBoundary>
    <Inner>{children}</Inner>
  </ErrorBoundary>
)

也就是说,如果您试图在不知道它们是什么的情况下渲染事物,就会有一点代码异味。我无法想象您只想尝试在 DOM 上抛出随机值的用例。

相关问题