目标
希望判断一个React节点的value是否是null这种空值,以便替换为符号-
原理
React Element 支持使用 node.props.value的方式获得节点的内容,但是React node有很多类型
要先判断一下再取值,使用
React.isValidElement(children)
判断是否为React Element。
代码
import * as React from 'react';
export const EMPTY_SYMBOL = '-';
const checkEmpty = (val: any) => (val === undefined || val === null || val === '');
export const noBlankElement = (children: React.ReactNode, blankSymbol: React.ReactNode = EMPTY_SYMBOL): '-' | React.ReactNode => {
try {
if (checkEmpty(children)) return blankSymbol;
if (React.isValidElement(children)) {
if (checkEmpty(children.props?.value)) {
const renderType = (children as React.ReactElement)?.type;
if (typeof renderType === 'function') {
const element = (renderType as Function)(children);
if (checkEmpty(element)) return blankSymbol;
if (element.type === React.Fragment && checkEmpty(children.props.children)) {
return blankSymbol;
}
}
}
}
} catch (e) {
return children;
}
return children;
};
单测:
import * as React from 'react';
import { renderTest, screen } from 'test/lib/helpers/intlTestHelper';
import { noBlankElement, EMPTY_SYMBOL } from 'components/qualityFlow/components/Table/utils/handler';
const testWrapper = (children: React.ReactNode) => renderTest(<>{noBlankElement(children)}</>);
// eslint-disable-next-line react/jsx-no-useless-fragment
const FragmentComponent = () => <>{null}</>;
describe('handler noBlankElement', () => {
describe('primitives', () => {
it('check empty string', () => {
testWrapper('');
expect(screen.queryByText(EMPTY_SYMBOL)).toBeInTheDocument();
});
it('check null', () => {
testWrapper(null);
expect(screen.queryByText(EMPTY_SYMBOL)).toBeInTheDocument();
});
it('check undefined', () => {
testWrapper(undefined);
expect(screen.queryByText(EMPTY_SYMBOL)).toBeInTheDocument();
});
it('check number 0', () => {
testWrapper(0);
expect(screen.queryByText(EMPTY_SYMBOL)).not.toBeInTheDocument();
});
it('check false', () => {
testWrapper(false);
expect(screen.queryByText(EMPTY_SYMBOL)).not.toBeInTheDocument();
});
});
describe('ReactElement', () => {
it('render empty React.Fragment', () => {
testWrapper(<FragmentComponent />);
expect(screen.queryByText(EMPTY_SYMBOL)).toBeInTheDocument();
});
it('render element directly', () => {
testWrapper(<div />);
expect(screen.queryByText(EMPTY_SYMBOL)).not.toBeInTheDocument();
});
});
});
Reference:
https://beta.reactjs.org/reference/react/isValidElement
https://stackoverflow.com/questions/29568721/getting-dom-node-from-react-child-element