web-dev-qa-db-ja.com

非同期データでコンポーネントを初期化します

私は、react + redux + thunkで選択ボックスのデータをロードする(つまり、アクションでディスパッチを呼び出す)方法と場所を理解しようとしています。 Appコンテナーのコンストラクターに入れるべきか、それともコンポーネント内にロードするべきか(私の例では「MyDropdown」)がわかりません。

私のメインアプリ:

import MyDropdown from '../components/mydropdown';
// Should i import my action here and then...
// import { loadData } from '../actions';

class App extends Component {
  render() {
    return (
      <div className="page-content">
        <div className="option-bar">
          // SEND it as a PROP inside MyDropdown... 
          <MyDropdown />
        </div>
      </div>
    );
  }
}
export default App;

私のコンポーネント

// OR.. Should i load it in my MyDropdown component here?
import { loadData } from '../actions';

class MyDropdown extends Component {
  // If i load it here on load, how do i do it?
  render() {
    return(
      <select>
         {renderOptions()}
      </select>
    );
  }
}

Appクラス内でcomponentDidMount()を試しましたが、機能しなかったようです。子コンポーネント内でアクションを呼び出すのではなく、すべて一元化されるため、初期化データを配置してアクションを呼び出すことは理にかなっているようです。また、起動時にロードする必要のある選択ボックスが複数あるので、Appクラスがかなり大きくなる可能性がありますが、それは正しい方法ですか?私はreactを学び始めたばかりなので、ベストプラクティスが何であるかわかりません。

13
mnsr

データコンポーネントをプレゼンテーションコンポーネントから分離する必要があります(投稿 ここ を参照)。

したがって、小さな例では、コンポーネントをレンダリングするために必要なすべてのデータをMyDropdownに渡す必要があります。これは、アプリ(または実際にビューをレンダリングするコンポーネントの親コンポーネント)でデータをフェッチすることを意味します。

ReactとReduxを使用しているため、 react-redux ライブラリは、プレゼンテーションコンポーネントに必要なデータをフェッチするコンテナを生成するためのヘルパー関数を提供します。

これを行うには、Appを次のように変更します。

import { connect } from 'react-redux'
import MyDropdown from '../components/mydropdown';
import { loadData } from '../actions';

// This class is not exported
class App extends Component {
  componentDidMount() {
    this.props.loadData()
  }
  render() {
    return (
      <div className="page-content">
        <div className="option-bar">
          <MyDropdown data={this.props.data}/>
        </div>
      </div>
    );
  }
}

function mapStateToProps(state) {
  const { data } = state
  return {
    data
  }
}

function mapDispatchToProps(dispatch) {
  return {
    loadData(){
      dispatch(loadData())
    }
  }
}

// Export a container that wraps App
export default connect(mapStateToProps, mapDispatchToProps)(App);

または、Appを同じに保ち、MyDropdownを次のように変更することもできます。

import { connect } from 'react-redux'
import { loadData } from '../actions';

// Exporting this allows using only the presentational component
export class MyDropdown extends Component {
  componentDidMount() {
    this.props.loadData()
  }
  render() {
    return(
      <select>
         {renderOptions(this.props.data)}
      </select>
    );
  }
}

function mapStateToProps(state) {
  const { data } = state
  return {
    data
  }
}

function mapDispatchToProps(dispatch) {
  return {
    loadData(){
      dispatch(loadData())
    }
  }
}

// By default, export the container that wraps the presentational component
export default connect(mapStateToProps, mapDispatchToProps)(MyDropdown);

どちらの場合も、最後にデフォルトとして実際にエクスポートされているものを確認してください。これはコンポーネントではありません。 connectの戻りです。この関数は、プレゼンテーションコンポーネントをラップし、データのフェッチとプレゼンテーションコンポーネントのアクションの呼び出しを担当するコンテナーを返します。

これにより、必要な分離が可能になり、プレゼンテーションコンポーネントの使用方法に柔軟性を持たせることができます。どちらの例でも、MyDropdownをレンダリングするために必要なデータがすでにある場合は、プレゼンテーションコンポーネントを使用して、データフェッチをスキップできます。

この完全な例は、Reduxのドキュメント ここ で見ることができます。

10
Rick Hanlon II