Enzyme ReactWrapper `.props()` 方法完全指南:安全读取根节点 Props 的正确姿势
发布时间:2026/9/20 22:34:03 作者:尧图编辑部 阅读量:1,286
` 方法完全指南:安全读取根节点 Props 的正确姿势)
Enzyme ReactWrapper.props()方法完全指南安全读取根节点 Props 的正确姿势【免费下载链接】enzymeJavaScript Testing utilities for React项目地址: https://gitcode.com/gh_mirrors/en/enzyme.props()是 Enzyme 中ReactWrapper由mount()产生的全量渲染包装器提供的一个核心只读方法用于获取包装器根节点完整的 props 对象。本指南以 docs/api/ReactWrapper/props.md 为骨架结合 ReactWrapper.js 与 RSTTraversal.js 的源码实现以及共享测试套件深入讲解其语义、与instance().props的本质区别、单节点约束与典型使用场景帮助你写出在 React 15/16 各版本下都稳定可靠的断言。方法签名与基本语义.props()的完整签名如下.props() Object返回类型Object即包装器根节点root node当前持有的全部 props 组成的普通对象。适用对象ReactWrapper由 mount() 创建也可用于ShallowWrapper由 shallow() 创建。约束条件必须是单节点包装器single-node wrapper即内部恰好包装了一个节点。如果包装器包含 0 个或 2 个及以上节点调用会直接抛错详见下文“单节点约束”一节。在官方文档中该方法被描述为一种访问节点 props 的可靠方式——这里的可靠是针对wrapper.instance().props而言的后者在 React 16 及以上版本中对无状态函数组件stateless functional components简称 SFC会失效因为 SFC 根本没有实例。相关内容可参见.instance() ReactComponent文档。为什么推荐.props()而不是instance().props在 React 15.x 时代函数组件同样会被创建出实例因此wrapper.instance().props可以正常工作。但从 React 16 开始函数组件不再拥有实例wrapper.instance()对这类组件返回null此时访问.props会抛出TypeError: Cannot read property props of null。ReactWrapper源码中 instance() 的实现 直接返回内部节点的instance字段instance() { return this.single(instance, () this[NODE].instance); }而.props()走的是完全独立的数据通路——它不依赖组件实例而是直接从渲染树节点RST node上读取 props 字段。因此无论目标组件是类组件还是函数组件.props()都能稳定工作这也是官方文档将其定位为可靠方式的根本原因。完整示例从挂载组件读取根节点 props以下示例完整复刻自官方文档演示了在mount场景下.props()与instance().props的行为差异import PropTypes from prop-types; function MyComponent(props) { const { includedProp } props; return ( div classNamefoo bar includedProp{includedProp}Hello/div ); } MyComponent.propTypes { includedProp: PropTypes.string.isRequired, }; const wrapper mount(MyComponent includedPropSuccess! excludedPropIm not included /); expect(wrapper.props().includedProp).to.equal(Success!); // Warning: .props() only returns props that are passed to the root node, // which does not include excludedProp in this example. // See the note above about wrapper.instance().props. console.log(wrapper.props()); // { children: Hello, className: foo bar, includedProp: Success! } console.log(wrapper.instance().props); // React 15.x - working as expected // { children: Hello, className: foo bar, includedProp: Success!, excludedProp: Im not included } console.log(wrapper.instance().props); // React 16.* - Uncaught TypeError: Cannot read property props of null这个示例揭示了两个关键点.props()只返回传给根节点的 props在上面的代码中根节点是MyComponent组件本身因此返回的是 JSX 中显式传入的 propsincludedProp、excludedProp再加上 React 隐式注入的children。注意示例里excludedProp虽然没有被组件使用但它确实作为 JSX 属性传给了组件所以理论上会出现在.props()返回对象中——文档注释中不包含 excludedProp的说法对应的更准确场景是当你对渲染后的 DOM 节点如div调用.props()时组件接收到的 props 中未透传到 DOM 上的部分不会被看到。这一点在共享测试中有明确区分见下文源码与测试验证一节。instance().props在 React 16 下对函数组件必然抛错由于函数组件没有实例instance()返回null访问null.props直接抛出TypeError。因此跨版本测试代码中应统一使用.props()。用.props()读取子节点.props()不仅能用于根节点也能作用于find()筛选出的任意子节点前提依然是单节点包装器。共享测试套件 props.jsx 验证了这一点const wrapper Wrap(( div classNamebax div classNamebaz onClick{fn} / div classNamefoo idfooId / /div )); expect(wrapper.find(.baz).props().onClick).to.equal(fn); expect(wrapper.find(.foo).props().id).to.equal(fooId);该测试同时证实.props()返回的是当前节点自身的 props而非祖先节点的——find(.baz)得到的是div classNamebaz onClick{fn} /的 props 对象。源码级实现原理核心实现一行委托ReactWrapper中 props() 的实现 极其简洁props() { return this.single(props, propsOfNode); }ShallowWrapper中 props() 的实现 与之完全一致。两者最终都调用RSTTraversal.js中导出的工具函数 propsOfNodeexport function propsOfNode(node) { return (node node.props) || {}; }这个工具函数对空节点做了兜底如果节点不存在返回空对象{}而不是抛错。propsOfNode是 Enzyme 渲染树遍历层RSTTraversal的通用基础设施除了.props()还被 selectors.js选择器属性匹配、Debug.js调试输出等模块复用是整个 props 读取链路的唯一事实来源。单节点约束single()守卫文档明确要求.props() 必须在单节点包装器上调用。这一约束由 single() 方法 强制实施single(name, fn) { const fnName typeof name string ? name : unknown; const callback typeof fn function ? fn : name; if (this.length ! 1) { throw new Error(Method ${fnName} is meant to be run on 1 node. ${this.length} found instead.); } return callback.call(this, this.getNodeInternal()); }也就是说如果包装器包含 0 个或 2 个以上节点例如find(div)命中了多个元素调用.props()会抛出形如Method props is meant to be run on 1 node. 2 found instead.的异常帮助你尽早发现测试断言目标不明确的问题。与浅渲染ShallowWrapper.props()的关键差异ShallowWrapper 的 props.md 中特别补充了一条ReactWrapper文档没有强调的注意点当在浅渲染包装器上调用.props()时返回的是组件渲染出的根节点上的 props而不是组件自身的 props。例如对Foo foohi barbye /执行浅渲染若Foo渲染为div className{bar} id{foo} /WrapRendered(...).props()浅渲染包装器返回{ className: bye, id: hi }——是Foo渲染结果中div节点的 propsmount(...).props()全量挂载包装器返回{ bar: bye, foo: hi }——是传给Foo组件本身的 props。共享测试 props.jsx 中通过isMount标志精确地区分了这两种场景无论类组件还是 SFC 行为一致。因此在使用.props()前务必先确认你的包装器来自mount()还是shallow()两者的根节点语义截然不同。典型应用场景对 props 做整体断言直接expect(wrapper.props()).to.eql({ ... })一次校验全部 props包含children等隐式属性。验证回调 prop 传递读取wrapper.props().onClick并手动调用配合异步 state 更新场景验证子组件 props 是否随之刷新见 props.jsx 中wrapper.find(TestSubComponent).props()的异步断言示例。作为.prop(key)的基础ReactWrapper中 prop(propName) 的实现 就是一行return this.props()[propName];也就是说.props()是单值读取.prop(key)的底层依赖理解前者是掌握后者的前提。相关方法.props()与以下 API 同属读取包装器当前状态的方法族官方文档互相引用.prop(key) Any按 key 读取根节点的单个 prop等价于this.props()[key]。.state([key]) Any读取根节点组件的 state仅类组件可用。.context([key]) Any读取根节点组件的 context仅类组件可用。.instance() ReactComponent读取底层组件实例注意 React 16 下函数组件返回null这正是.props()被推荐的原因。三者共有的特征是都必须作用于单节点包装器且都受single()约束区别在于 props 读取自渲染树节点不依赖实例兼容函数组件而 state/context 读取自组件实例仅类组件可用。【免费下载链接】enzymeJavaScript Testing utilities for React项目地址: https://gitcode.com/gh_mirrors/en/enzyme创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考