首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带有React +Redux的选择器。将数据传递给子组件

带有React +Redux的选择器。将数据传递给子组件
EN

Stack Overflow用户
提问于 2018-07-12 12:28:43
回答 1查看 1.8K关注 0票数 2

我有一个React应用程序,我正在尝试使用Reux-ORM,并且我正在与选择器进行斗争。我有一个简单的应用程序

代码语言:javascript
复制
// /models/team.js
import { Model, many, attr } from 'redux-orm';
import Player from './player';

class Team extends Model {
  static reducer(action, Team, session) {
    [...]
  }
}
Team.modelName = "Team";
Team.fields = {
  id: attr(),
  players: many('Player;),
}

代码语言:javascript
复制
// /models/player.js
import { Model, attr } from 'redux-orm';

class Player extends Model {
  static reducer(action, Player, session) {
    [...]
  }
}
Player.modelName = "Player";
Player.fields = {
  id: attr(),
}

我将它们登记在ORM中如下:

代码语言:javascript
复制
// /selectors/selector.js
import { ORM } from 'redux-orm';

import Team from '../models/team';
import Player from '../models/player';

const orm = new ORM();
orm.register(Team, Player);

export default orm;

到目前一切尚好。现在,我想有一个反应组件,使所有球队的名单与所有球员。所以我做的第一件事就是写一个选择器:

代码语言:javascript
复制
// /selectors/selector.js
import { createSelector } from "redux-orm";
import orm from "../models/index";

export const teams = createSelector(
  orm,
  state => state.orm,
  session => {
    return session.Team.all().toRefArray();
  }
);

这就给出了球队的名单,但还没有给出相关的球员。因此,在我的组件中,如果我添加了一个函数teams,就可以使用我的道具中的const mapStateToProps = state => ({teams: teams(state)});

但现在我的问题是,什么是最好的方法来获得团队特有的球员?我是否将它们添加到选择器中返回的团队中?还是我写了一个单独的选择器?我是否会直接将球员传递给组件,或者更确切地说,在团队组件中创建一个单独的组件?

代码语言:javascript
复制
class Teams extends React.Components {
   render() {
    return this.props.teams.map(team => {
      /* Option 1: */
      const teamPlayer = team.players // returned by initial selector
      /* Option 2: */
      const teamPlayers = [some call to selector based on 'team'];
      /* Option 3: */
      // Don't pass on the players but the id instead
      return (
        <Team
          /* Option 1 & 2: */
          players= {teamPlayers}
          /* Option 3: */
          teamId = {team.id} // and within the Team component make a selector call
        />
   }
}

实现上,我被困在做选择器上,找不到redux-orm v0.19的例子,从概念上来说,我仍然不确定哪条路是最好的。所有的帮助都非常感谢!

EN

回答 1

Stack Overflow用户

发布于 2018-07-13 10:37:38

更新(2019-09-30):

从v0.14开始,有一种更简单的方法来创建公共选择器。首先,可以这样编写teams选择器:

代码语言:javascript
复制
const teams = createSelector(orm.Team);

类似于您对QuerySet的操作,您可以创建一个选择器来检索团队成员的引用数组:

代码语言:javascript
复制
const teamPlayers = createSelector(orm.Team.players);

使用related,您可以简单地将一个团队传递给React组件,然后该组件在存储更新时获取所有相关数据。

代码语言:javascript
复制
function TeamList(props) {
  const teams = createSelector(state => teams(state));
  return (
    <ul>
      {teams.map((team, i) => (
        <Team key={team.id} team={team} />)
      )}
    </ul>
  );
}

function Team({ team }) {
  const players = useSelector(state => teamPlayers(state, team.id));
  return (
    <div>
      {team.name}: {players.map(player => player.name).join(', ')}
    </div>
  );
}

您也可以在父组件中使用teamPlayers选择器,但根据我的经验,如果组件本身检索其依赖项,则通常更有利于重用。因此,有时甚至最好将team.id传递给Team而不是整个team ref。不是在这里做的,因为这看起来毫无用处。

请注意,teams(state)按插入顺序返回所有团队。不要尝试像teams(state)[team.id]那样对其进行索引,因为在迭代时,team.id通常与数组中的团队索引不匹配。要获取单个团队,传递它的主键(类似于teams(state, team.id) )。有关更多细节,请看一下我们的新文档

简单的回答是:没有正确的方法。以前有人问过这里

但是,最简单的方法是直接添加播放器引用,如下所示:

代码语言:javascript
复制
export const teams = createSelector(
  orm,
  state => state.orm,
  ({ Team }) => {
    return Team.all().toModelArray().map(team => ({
      ...team.ref,
      players: team.players.toRefArray(),
    }));
  }
);

这将允许您作为团队对象的数组属性直接访问您的球员,并且您不需要添加任何其他内容。不过,如果您想重用选择器而不访问播放机数组,则可能存在开销的缺点。在您的观点中,您可以传递整个团队引用或其部分作为支持:

代码语言:javascript
复制
<Team
  // either entire team object
  team={team}

  // or each field individually
  teamId={team.id}
  players={team.players}
/>

或者,您可以为需要查询的每个关系创建一个单独的选择器:

代码语言:javascript
复制
export const teamPlayers = createSelector(
  orm,
  state => state.orm,
  ({ Team }) => {
    return Team.all().toModelArray().reduce(map, team => ({
      ...map,
      [team.id]: team.players.toRefArray(),
    }));
  }
);

<Team
  // either entire team object
  team={team}
  teamPlayers={teamPlayers}

  // or each field individually
  teamId={team.id}
  players={teamPlayers[team.id]}
/>

这有一个相当明显的问题:每次您想要使用关系访问器时,都需要添加一个选择器,或者至少是最小的样板。

组件内部的调用选择器本身并不是这样做的,因为只有在存储更新时才会调用mapStateToProps。我强烈反对第三种选择,除非您愿意并且有充分的理由再次在子组件中使用connect

如果你觉得这一切都很混乱,你肯定不是一个人--我已经考虑了一段时间如何改进这个问题。我们可以让Redux提供一种更简单的方法来创建或访问每个人都需要的这类选择器。现在它非常灵活,但还不太方便。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51305719

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档