我正在开发 React 应用程序,这是我用于组件的方法:我使用 PropTypes 验证验证我希望收到的道具,但我仍然分配默认值以避免它如果接收到的数据出现问题,则中断。
最近有人告诉我,我们不应该这样做,道具是我们对父级的期望,如果不遵守合同让组件中断。
哪种方法是正确的,优缺点是什么?
我的一些考虑作为思考的食物..
按照我最初的方法,在测试中,我明确测试传递给被测组件的一些无效数据的默认值,并期望仍然打印出有效的快照。测试不会因为一些错误的数据而失败,但我会打印出 PropTypes 验证警告(如果需要,可以将其转换为错误 - 我认为 - 或者在测试中将它们模拟出来)。
测试和实际应用程序中的这些警告比仅仅看到“无法从未定义中读取 'someProp'”或类似错误(并让 React 渲染循环中断)更简洁明了。propType 验证直接并清楚地告诉您您做错了什么(您将错误的类型作为 prop 传递,该 prop 完全丢失等)。
使用第二种方法,测试失败,因为应用程序中断。我认为只有在测试覆盖率真的很好(90/100%)的情况下,这才是一个好方法,否则这是一个风险——它可能会上线并在破坏产品声誉的边缘情况下崩溃。重构或需求更改经常发生,并且某些边缘情况可能最终会产生破坏应用程序的不需要的数据,并且在自动或手动测试中没有捕获到。
这意味着当应用程序运行时,由于某些错误数据,代码可能会在父组件中中断,并且整个应用程序停止工作,而在第一种情况下,应用程序是有弹性的,只是以受控方式显示一些空字段。
想法?
下面是一个简化的例子:
反应组件
import React from 'react';
import PropTypes from 'prop-types';
import styles from './styles.css';
export const App = ({ person : { name, surname, address, subscription } = {} }) => (
<div style={styles.person}>
<p> {person.name} </p>
<p> {person.surname} </p>
<p> {person.address} </p>
<div>
{
person.subscription &&
<Subscription details={person.subscription} />
}
</div>
</div>
);
// PS. this is incorrect in this example (as pointed out in an answer). Real code used inline initialization.
// App.defaultProps = {
// person: { subscription: undefined },
// };
App.propTypes = {
person: PropTypes.shape({
name: PropTypes.string.isRequired,
surname: PropTypes.string.isRequired,
address: PropTypes.string,
subscription: PropTypes.object,
}).isRequired,
};
测试
import React from 'react';
import { shallow } from 'enzyme';
import { mockOut } from 'testUtils/mockOut';
import { App } from '../index.js';
describe('<App>', () => {
mockout(App, 'Subscription');
it('renders correctly', () => {
const testData = {
name: 'a name',
surname: 'a surname',
address: '1232 Boulevard Street, NY',
subscription: { some: 'data' },
}
const tree = shallow(<App person={testData} />);
expect(tree.html()).toMatchSnapshot();
});
it('is resilient in case of bad data - still generates PropTypes validation logs', () => {
const tree = shallow(<App person={undefined} />);
expect(tree.html()).toMatchSnapshot();
});
});
更新:
问题的主要焦点是是否为标有 isRequired 的道具分配默认值是否正确(而不是让它们的缺席破坏组件)