web-dev-qa-db-ja.com

ReactJS-状態を持ち上げるvsローカル状態を維持する

私の会社では、WebアプリケーションのフロントエンドをReactJSに移行しています。 Reduxなしでcreate-react-app(v16に更新)を使用しています。今、私は次の画像によって構造を簡素化できるページにこだわっています:

Page structure

3つのコンポーネント(SearchableList、SelectableList、およびMap)によって表示されるデータは、MainContainerのcomponentDidMount()メソッドの同じバックエンドリクエストで取得されます。このリクエストの結果はMainContainerの状態で保存され、ほぼこのような構造になります。

_state.allData = {
  left: {
    data: [ ... ]
  },
  right: {
    data: [ ... ],
    pins: [ ... ]
  }
}
_

LeftContainerは、MainContainerからprop _state.allData.left_を受け取り、_props.left.data_を再びSearchとしてSearchableListに渡します。

RightContainerは、MainContainerから__state.allData.right_をpropとして受け取り、_props.right.data_をSelectableListに、_props.right.pins_をMapに渡します。

SelectableListはチェックボックスを表示して、そのアイテムに対するアクションを許可します。 SelectableListコンポーネントのアイテムでアクションが発生するたびに、マップピンに副作用が生じる可能性があります。

SelectableListで表示されるアイテムのすべてのIDを保持するリストをRightContainerの状態で保存することにしました。このリストは、SelectableListとMapの両方に小道具として渡されます。次に、SelectableListにコールバックを渡します。選択が行われるたびに、RightContainer内のIDのリストが更新されます。新しいプロップはSelectableListとMapの両方に到着するため、両方のコンポーネントでrender()が呼び出されます。

これはうまく機能し、SelectableListとMapに発生する可能性のあるすべてをRightContainer内に保持するのに役立ちますが、これがlifting-state-upおよびsingle-source- of-truthコンセプト。

実行可能な代替案として、MainContainerの__selected_の各項目に_state.right.data_プロパティを追加し、選択コールバックを3レベルSelectableListに渡し、MainContainerで可能なすべてのアクションを処理することを考えました。ただし、選択イベントが発生するとすぐに、LeftContainerとRightContainerのロードが強制的に行われ、特にLeftContainerで不要なshouldComponentUpdate()を回避するためにrender()などのロジックを実装する必要が生じます。

アーキテクチャとパフォーマンスの観点からこのページを最適化する最適なソリューションはどれですか?

以下に、状況を理解するのに役立つ私のコンポーネントの抜粋があります。

MainContainer.js

_class MainContainer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      allData: {}
    };
  }

  componentDidMount() {
    fetch( ... )
      .then((res) => {
        this.setState({
          allData: res
        });
      });
  }

  render() {
    return (
      <div className="main-container">
        <LeftContainer left={state.allData.left} />
        <RightContainer right={state.allData.right} />
      </div>
    );
  }
}

export default MainContainer;
_

RightContainer.js

_class RightContainer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedItems: [ ... ]
    };
  }

  onDataSelection(e) {
    const itemId = e.target.id;
    // ... handle itemId and selectedItems ...
  }

  render() {
    return (
      <div className="main-container">
        <SelectableList
          data={props.right.data}
          onDataSelection={e => this.onDataSelection(e)}
          selectedItems={this.state.selectedItems}
        />
        <Map
          pins={props.right.pins}
          selectedItems={this.state.selectedItems}
        />
      </div>
    );
  }
}

export default RightContainer;
_

前もって感謝します!

18
LucioB

これに関する私の正直なアドバイス。経験から:

Reduxは簡単です。理解とスケーリングは簡単ですが、特定のユースケースではReduxを使用する必要があります。

Reduxはアプリをカプセル化するため、次のようなものを保存することを考えることができます。

  • 現在のアプリのロケール
  • 現在の認証済みユーザー
  • どこかからの現在のトークン

世界規模で必要なもの。 react-reduxでは、コンポーネントで@ connectデコレーターも使用できます。以下のようなので:

@connect(state => ({ 
   locale: state.locale,
   currentUser: state.currentUser
}))
class App extends React.Component

これらはすべて小道具として渡され、接続はアプリのどこでも使用できます。スプレッド演算子でグローバルな小道具を渡すことをお勧めしますが

<Navbar {...this.props} />

アプリ内の他のすべてのコンポーネント(または「ページ」)は、独自のカプセル化された状態を実行できます。たとえば、[ユーザー]ページで独自の操作を実行できます。

class Users extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      loadingUsers: false,
      users: [],
    };
  }
......

ロケールとcurrentUserは、コンテナコンポーネントから渡されるため、小道具を介してアクセスします。

このアプローチは私がそれを複数回やったことで機能します。

しかし、React=子どもたち。

欠点:

  • あなたはそれらを内部レベルのコンポーネントに伝え続ける必要があります
  • 内部レベルのコンポーネントから状態を更新するには、状態を更新する関数を渡す必要があります。

これらの欠点は、管理するのが少し退屈で面倒です。それがReduxが構築された理由です。

私が助けてくれたことを願っています。幸運を

7
João Cunha

Reduxを使用することで、このようなコールバックを回避し、1つのストアで全体の状態を維持できます-したがって、親コンポーネントを接続コンポーネントにし、左右のコンポーネントをダムコンポーネントにし、親から子に取得した小道具を渡すだけで、この場合、コールバックについて心配する必要はありません。

1
monkeyjs