我有一个React应用程序,我正在尝试使用Reux-ORM,并且在选择器方面苦苦挣扎。我有一个带有标准化数据的简单应用
// /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;),
}
和
// /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如下:
// /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;
到目前为止,一切都很好。现在,我想拥有一个React组件,该组件可以呈现所有玩家所有团队的列表。所以我要做的第一件事是编写一个选择器:
// /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)});
但是现在我的问题是,获得团队特定球员的最佳方法是什么?是否将它们添加到选择器中返回的团队中?还是我写一个单独的选择器?我会直接将玩家传递给组件,还是在团队组件中创建一个单独的组件?
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
的这种情况找到示例,从概念上讲,我仍然不确定哪种方法最好。感谢所有帮助!
答案 0 :(得分:1)
简单的答案是:没有正确的方法。之前here已经有人问过。
但是,最简单的方法是像这样直接添加播放器引用:
export const teams = createSelector(
orm,
state => state.orm,
({ Team }) => {
return Team.all().toModelArray().map(team => ({
...team.ref,
players: team.players.toRefArray(),
}));
}
);
这将使您可以直接作为团队对象的数组属性访问玩家,而无需添加其他任何内容。但是,如果您想在不访问players数组的情况下重用选择器,则可能会有开销。在您看来,您可以将整个团队参考或部分参考作为支持:
<Team
// either entire team object
team={team}
// or each field individually
teamId={team.id}
players={team.players}
/>
或者,您可以为每个需要查询的关系创建一个单独的选择器:
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-ORM提供一种更轻松的方法来创建或访问每个人都需要的选择器。现在,它非常灵活,但还不太方便。