web-dev-qa-db-ja.com

まだマウントされていないコンポーネントでsetStateを呼び出すことはできません

この警告メッセージに直面するのは初めてです。

まだマウントされていないコンポーネントでsetStateを呼び出すことはできません。

フォロー:

これは何もしませんが、アプリケーションのバグを示している可能性があります。代わりに、this.stateに直接割り当てるか、MyComponentコンポーネントで目的の状態を持つstate = {};クラスプロパティを定義します。

まだマウントされていない」の部分は、問題を引き起こす唯一の方法は、ボタンを表示するためにマウントする必要があるコンポーネントからボタンをクリックすることによって機能します。コンポーネントは、いつでもアンマウントされません。

このダミーコンポーネントは、アプリでエラーを再現します。

import PropTypes from 'prop-types'
import React from 'react'

export default class MyComponent extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
      initial: 'state'
    }
    this.clickMe = this.clickMe.bind(this)
  }

  clickMe () {
    this.setState({
      some: 'new state'
    })
  }

  render () {
    return (
      <div>
        <button onClick={this.clickMe}>click</button>
      </div>
    )
  }
}

私は使っている:

"react": "16.3.2",
"react-dom": "16.3.2",
"mobx": "4.2.0",
"mobx-react": "5.1.2",

最新のReact/mobxバージョンの何かを見逃しましたか? (コンポーネントはmobx関連のものを使用しませんが、その親はmobx-reactオブザーバーです)

編集:

コンポーネントインスタンスに関連するものが存在する必要があります。詳細な調査により、場合によっては、render関数内にハンドラーを作成するとこの警告が消えることが示されていますが、すべての場合ではありません。

class MyComponent extends React.component {
  constructor (props) {
    // ...
    this.clickMeBound = this.clickMe.bind(this)
  }

  clickMe () {
    ...
  }

  render () {
    // works
    <button onClick={() => {this.clickMe()}}>click arrow in render</button>

    // warning: Can't call setState on a component that is not yet mounted.
    <button onClick={this.clickMeBound}>click bound</button>
  }
}

編集2:

Webpack configのエントリから「react-hot-loader/patch」を削除しましたが、このような奇妙な問題はなくなりました。エラーメッセージ自体はまだ奇妙であり、これがコンソールに警告を引き起こすので、私はこれを答えとしていません。すべてがうまく動作します。

14
Kev

@ Amida のように、ホットローダーが問題のようです。使用している人

app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
    HotModuleReplacement = true,
    ReactHotModuleReplacement = true
});

startup.csでそれを削除すると、問題は消えます。理由はわかりませんが、これが現在の回避策です。

編集:

「react-hot-loader」および「webpack-hot-middleware」を最新バージョンに更新すると、問題が修正されました

1
Antoan Elenkov

このコード行をコードに追加するだけです

export default class MyComponent extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
       initial: 'state',
       some: ''          // <-------  this line
    }
   this.clickMe = this.clickMe.bind(this)
  }

 clickMe () {
   this.setState({
     some: 'new state'
   })
  }

 render () {
   return (
     <div>
       <button onClick={this.clickMe}>click</button>
     </div>
   );
  }
}
1

テストの1つでこのエラーが発生している場合、コンポーネントにアクセスする前に、コンポーネントをrenderする必要があるかもしれません(つまり、単にlet app = new App;を行うだけでは不十分です)。レンダリングは効果的に mountこの他の回答で説明されているように、コンポーネントとその子 を使用すると、 setStateエラーをトリガーせずに操作を実行する結果オブジェクト。簡単なApp.test.jsの例:

import App from './App';

it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(<App />, div); // <-- App component mounted here
  // without JSX: ReactDOM.render(React.createElement(App), div)
  ReactDOM.unmountComponentAtNode(div);
});

test('array length decreased after removal', () => {
  const div = document.createElement('div');
  let app = ReactDOM.render(<App />, div); // <-- App component mounted here
  const origArrLen = app.state.arr.length;

  app.removeAtIndex(0);
  expect(app.state.arr.length).toEqual(origArrLen - 1);
  ReactDOM.unmountComponentAtNode(div);
});

Appコンポーネントが持つ可能性のある場所:

class App extends Component {
  state = {
    arr: [1,2,3]
  };

  removeAtIndex = index => {
    const { arr } = this.state;
    this.setState({ arr: arr.filter((el, i) => i !== index) });
  };
  // render() { return ( ... ) }
}
0
CPHPython