Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript prevState在酶试验中未定义,但在组件中定义_Javascript_Reactjs_Enzyme - Fatal编程技术网

Javascript prevState在酶试验中未定义,但在组件中定义

Javascript prevState在酶试验中未定义,但在组件中定义,javascript,reactjs,enzyme,Javascript,Reactjs,Enzyme,看到一个奇怪的问题,prevState在componentDidUpdate中未定义,但在浏览器中运行组件时定义 我在构造函数中设置了state,并且在prevState上有一个值的check-in-componentdiddupdate componentDidUpdate(prevProps, prevState) { const { showForm } = this.state; if (prevState.showForm && !showForm

看到一个奇怪的问题,
prevState
componentDidUpdate
中未定义,但在浏览器中运行组件时定义

我在构造函数中设置了state,并且在
prevState
上有一个值的check-in-componentdiddupdate

  componentDidUpdate(prevProps, prevState) {
    const { showForm } = this.state;

    if (prevState.showForm && !showForm) {
      return this.input.current.focus();
    }

  }
以下是酶试验:

 it("should call focus on input if form was shown, and now form is open", () => {
    component = mount(<Component {...props} />);
    const prevProps = component.props();
    const prevState = {
      ...component.state(),
      showForm: true
    };
    const focusSpy = sinon.spy(component.instance().input.current, "focus");
    component.instance().componentDidUpdate(prevProps, prevState);
    expect(focusSpy).to.have.been.called;
  });
it(“如果显示了表单,并且现在表单已打开,则应调用focus on input”,()=>{
组件=安装();
const prevProps=component.props();
const prevState={
…组件。状态(),
展示形式:真实
};
const focusSpy=sinon.spy(component.instance().input.current,“focus”);
component.instance().componentDidUpdate(prevProps,prevState);
expect(focusSpy).to.have.been.call;
});
这种方法是有效的,但这仅仅是因为我从酶测试中调用了
componentdiddupdate
,并通过了
prevState
。 理想情况下,我希望避免这种情况——并且只需要定义prevState——因为组件在浏览器中实际工作时就是这样


处理此问题的模式是什么?

您的测试不应该显式调用
componentdiddupdate
。下面是一个我已经验证过的组件和测试,它只是多次调用
setState
,以触发要测试的场景

MyComp.js

import React from "react";

class MyComp extends React.PureComponent {
  constructor(props) {
    super(props);
    this.state = { showForm: false };
    this.input = React.createRef();
  }
  toggleShowForm = () => {
    this.setState({ showForm: !this.state.showForm });
  };
  componentDidUpdate(prevProps, prevState) {
    console.log(
      "componentDidUpdate prevProps: " +
        JSON.stringify(prevProps) +
        "; prevState: " +
        JSON.stringify(prevState) +
        "; this.state: " +
        JSON.stringify(this.state)
    );
    if (prevState.showForm && !this.state.showForm) {
      console.log("setting focus");
      this.input.current.focus();
    }
  }

  render() {
    return (
      <>
        <input type="text" ref={this.input} />
        <br />
        <button onClick={this.toggleShowForm}>Toggle showForm</button>
      </>
    );
  }
}

export default MyComp;
import React from "react";
import { mount } from "enzyme";
import MyComp from "./MyComp";
import sinon from "sinon";

it("should call focus on input if showForm goes from true to false", () => {
  const myCompWrapper = mount(<MyComp />);
  console.log("before first setState");
  const focusSpy = sinon.spy(myCompWrapper.instance().input.current, "focus");
  myCompWrapper.instance().setState({ showForm: true });
  expect(focusSpy.called).toEqual(false);
  console.log("before second setState");
  myCompWrapper.instance().setState({ showForm: false });
  expect(focusSpy.called).toEqual(true);
});
以下是此测试生成的控制台日志:

  • 在第一次设定状态之前
  • componentDidUpdate-prevProps:{};prevState:{“showForm”:false};this.state:{“showForm”:true}
  • 在第二次设定状态之前
  • componentDidUpdate-prevProps:{};prevState:{“showForm”:true};this.state:{“showForm”:false}
  • 设置焦点
下面是一个代码沙盒,您可以在其中执行此测试:


我更喜欢完全摆脱实例方法。在RYANS建议中进行一些编辑,以便您可以比较

it("should call focus on input if form was shown, and now form is open", () => {
    component = mount(<Component {...props} />);
    // Since you want your prevState.formOpen to be true, first get it in that state
    // This will trigger a re-render and componentDidUpdate, 
    // but you don't care about this execution of componentDidUpdate 
    // (though you could verify that "focus" does NOT get called in this case)
    component.setState({formOpen: true});
    // Then set up your spy

    expect(wrapper.find('input:focus').exists()).to.false;
    // You do this by changing the state and letting React do its thing
    // which will include React calling componentDidUpdate -- you should not
    // call it yourself.
    component.setState({formOpen: false});
    expect(wrapper.find('input:focus').exists()).to.true;
});
it(“如果显示了表单,并且现在表单已打开,则应调用focus on input”,()=>{
组件=安装();
//既然您希望prevState.formOpen为true,请首先在该状态下获取它
//这将触发重新渲染和组件更新,
//但是您不关心componentDidUpdate的执行
//(尽管您可以验证在这种情况下不会调用“focus”)
setState({formOpen:true});
//那就安排你的间谍
expect(wrapper.find('input:focus').exists()).to.false;
//您可以通过更改状态并让React执行其操作来实现这一点
//其中包括React调用componentDidUpdate——您不应该
//你自己说吧。
setState({formOpen:false});
expect(wrapper.find('input:focus').exists()).to.true;
});

componentDidUpdate中的测试错误是为了响应您在测试中做了什么?你在做什么来触发它?你不应该直接调用
component.instance().componentDidUpdate()
。您应该调用
component.update()
或其他方法之一,以使Ezyme/React调用
componentDidUpdate
。我知道这是一种反模式,但这是定义prevState的唯一解决方法。这很奇怪-我认为这应该有一个默认值。@zero\u cool我更新了我的答案,试图更清楚地表达我的意思。@zero\u cool我用一个工作示例更新了我的答案。您可以在我提供的CodeSandbox中运行测试。查看您在组件的构造函数中设置的初始状态以及当您遇到
prevState
undefined错误时测试代码的外观(而不是解决该问题时的外观)会很有帮助。this.state={formOpen:false}你有两个状态变量吗?
formOpen
showForm
?或者应该
prevState。在
componentdiddupdate
中的showForm
实际上是
prevState.formOpen
?很好的捕获-它应该只有一个变量-我更新了我的问题来反映这一点。我很想这样写,但是如果我不止一次设置了这个状态,这也很奇怪。你能在这里写下你的测试用例,然后把新的CodeSandboxURL发回给我吗?