我有一个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;到目前一切尚好。现在,我想有一个反应组件,使所有球队的名单与所有球员。所以我做的第一件事就是写一个选择器:
// /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的例子,从概念上来说,我仍然不确定哪条路是最好的。所有的帮助都非常感谢!
发布于 2018-07-13 10:37:38
更新(2019-09-30):
从v0.14开始,有一种更简单的方法来创建公共选择器。首先,可以这样编写teams选择器:
const teams = createSelector(orm.Team);类似于您对QuerySet的操作,您可以创建一个选择器来检索团队成员的引用数组:
const teamPlayers = createSelector(orm.Team.players);使用related,您可以简单地将一个团队传递给React组件,然后该组件在存储更新时获取所有相关数据。
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) )。有关更多细节,请看一下我们的新文档。
简单的回答是:没有正确的方法。以前有人问过这里。
但是,最简单的方法是直接添加播放器引用,如下所示:
export const teams = createSelector(
orm,
state => state.orm,
({ Team }) => {
return Team.all().toModelArray().map(team => ({
...team.ref,
players: team.players.toRefArray(),
}));
}
);这将允许您作为团队对象的数组属性直接访问您的球员,并且您不需要添加任何其他内容。不过,如果您想重用选择器而不访问播放机数组,则可能存在开销的缺点。在您的观点中,您可以传递整个团队引用或其部分作为支持:
<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提供一种更简单的方法来创建或访问每个人都需要的这类选择器。现在它非常灵活,但还不太方便。
https://stackoverflow.com/questions/51305719
复制相似问题