如何测试方法 shouldComponentUpdate?
Posted
技术标签:
【中文标题】如何测试方法 shouldComponentUpdate?【英文标题】:How do I test the method shouldComponentUpdate? 【发布时间】:2019-12-29 17:13:12 【问题描述】:我想测试该方法,shouldComponentUpdate
,但我编写的测试没有捕捉到副作用。我该如何测试?
我已经尝试过这里提出的解决方案,但存在一些问题,我将在代码中显示:How to unit test React Component shouldComponentUpdate method
我尝试过使用shallow
而不是mount
,但是当我这样做时,我的测试在这一点上失败了:
expect(shouldComponentUpdate).to.have.property("callCount", 1);
// AssertionError: expected [Function: proxy] to have a property 'callCount' of 1, but got 0
这是我的组件的shouldComponentUpdate
函数:
shouldComponentUpdate(nextProps, nextState)
if (this.props.storageValue !== nextProps.storageValue)
localStorage.setItem(constantFile.storageKey, nextProps.storageValue);
localStorage.setItem(constantFile.timestampKey, now());
this.setState(
newStorage: nextProps.storageValue
);
return true;
...
return false;
这是我的测试:
it("Test shouldComponentUpdate", () =>
/* eslint-disable one-var */
const wrapper = mount(
<Provider store=store>
<MyComponent />
</Provider>),
shouldComponentUpdate = sinon.spy(CapitalHomeAccessPointContainer.prototype, "shouldComponentUpdate");
wrapper.setProps(
storageValue: true
);
expect(shouldComponentUpdate).to.have.property("callCount", 1);
expect(shouldComponentUpdate.returned(true)).to.be.equal(true);
expect(localStorage.getItem(constantFile.timestampKey)).to.equal(someExpectedTimestamp);
);
expect(shouldComponentUpdate).to.have.property("callCount", 1);
失败
AssertionError: expected false to equal true
为什么会这样?我认为shouldComponentUpdate
应该返回true
?后来,我希望测试状态和本地存储的副作用,但我不明白这个错误。
【问题讨论】:
需要进行状态更改才能触发shouldComponentUpdate
。您还应该测试函数的结果,而不是如果它被调用。
我认为文档说,“使用 shouldComponentUpdate() 让 React 知道组件的输出是否不受当前状态或道具变化的影响。默认行为是在每个状态上重新渲染更改,并且在绝大多数情况下,您应该依赖默认行为”。 https://reactjs.org/docs/react-component.html#shouldcomponentupdate
所以我认为如果在 shouldComponentUpdate
中指定,道具的变化也应该触发 true?
您还提到要测试该功能的副作用。我也尝试这样做。 ```expect(wrapper.find("MyComponent").state("newStorage")).to.be.true; ``` 导致这个错误:``` AssertionError: expected false to be true ```
【参考方案1】:
您正在处理的 shouldComponentUpdate 生命周期是错误的。你不在其中setState
,而是只返回一个boolean
(true 或false)让React 知道何时重新渲染DOM。这允许您阻止来自外部道具的更新。例如:
shouldComponentUpdate(nextProps, nextState)
return this.state.newStorage !== nextState.newStorage
上述状态:如果当前 newStorage 状态与下一个 newStorage 状态不匹配,则重新渲染组件。 以上内容会阻止 prop 更改重新渲染组件。如果您更改了 storage
道具,它不会更新此组件,因为状态没有更改。您想使用 shouldComponentUpdate 来防止不必要的双重重新渲染和/或防止父组件的重新渲染不必要地重新渲染子组件。在这种情况下,您不需要使用此生命周期方法。
相反,您应该使用 static getDerivedStateFromProps 属性来更新渲染前的状态,或者使用 componentDidUpdate 来更新渲染后的状态。
在您的情况下,由于您只想在this.props.storageValue
更改时更新状态,因此您应该使用componentDidUpdate
:
componentDidUpdate(prevProps)
if (this.props.storageValue !== prevProps.storageValue)
localStorage.setItem(constantFile.storageKey, nextProps.storageValue);
localStorage.setItem(constantFile.timestampKey, now());
this.setState( newStorage: nextProps.storageValue );
上面检查当前的 props 是否与之前的 props 不匹配,然后更新状态以反映变化。
您将无法使用static getDerivedStateFromProps
,因为没有新旧道具之间的比较,而只是与传入道具和当前状态的比较。也就是说,如果您将某些内容存储在与存储道具直接相关的状态中,则可以使用它。一个示例可能是,如果您将密钥从道具存储到状态中。如果 props 键要更改并且它与状态中的当前键不匹配,那么它将更新状态以反映键更改。在这种情况下,您将返回 object
以更新状态或返回 null
以不更新状态。
例如:
static getDerivedStateFromProps(props, state)
return props.storage.key !== state.storageKey
? storageKey: props.storage.key
: null
在测试方面,您需要手动更新 props 以影响状态更改。通过针对状态更改进行测试,您将间接针对 componentDidUpdate
进行测试。
例如(你必须mock localStorage,否则状态不会更新——我还建议export
ing class
并导入它,而不是使用 Redux 连接组件):
import MyComponent from "../MyComponent.js";
const initialProps = storageValue: "" ;
describe("Test Component", () =>
let wrapper;
beforeEach(() =>
wrapper = mount(<MyComponent ...initialProps />);
)
it("updates 'newStorage' state when 'storageValue' props have changed, () =>
wrapper.setProps( storageValue: "test" );
expect(wrapper.state('NewStorage')).toEqual(...); // this should update NewStorage state
wrapper.setProps( someOtherProp: "hello" );
expect(wrapper.state('NewStorage')).toEqual(...); // this should not update NewStorage state
);
);
【讨论】:
以上是关于如何测试方法 shouldComponentUpdate?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 React 保留 componentWillReceiveProps 和 shouldComponentUpdate 方法?
[react] shouldComponentUpdate方法是做什么的
React Hooks - 我如何实现 shouldComponentUpdate?
如何将 shouldComponentUpdate 与 React Hooks 一起使用?