我正在创建的应用程序有很多实体和关系(数据库是关系).为了得到一个想法,有25个以上的实体,它们之间有任何类型的关系(一对多,多对多).
该应用程序是基于React + Redux的.为了从商店获取数据,我们使用了Reselect库.
我面临的问题是当我试图从商店获得一个与其关系的实体时.
为了更好地解释这个问题,我创建了一个简单的演示应用程序,它具有类似的架构.我将重点介绍最重要的代码库.最后,我将包括一个片段(小提琴),以便与它一起玩.
我们有书籍和作者.一本书有一位作者.一位作者有很多书.尽可能简单.
const authors = [{
id: 1,
name: 'Jordan Enev',
books: [1]
}];
const books = [{
id: 1,
name: 'Book 1',
category: 'Programming',
authorId: 1
}];
Run Code Online (Sandbox Code Playgroud)
商店采用扁平结构,符合Redux最佳实践 - 规范状态.
这是书籍和作者商店的初始状态:
const initialState = {
// Keep entities, by id:
// { 1: { name: '' } }
byIds: {},
// Keep entities ids
allIds:[]
};
Run Code Online (Sandbox Code Playgroud)
组件组织为容器和演示文稿.
<App /> 组件充当Container(获取所有需要的数据):
const mapStateToProps = state => ({
books: …Run Code Online (Sandbox Code Playgroud) 如何将其他参数传递给组合选择器?我在尝试着
•获取数据
•过滤数据
•通过myValue向我的数据集/组数据添加自定义值
export const allData = state => state.dataTable
export const filterText = state => state.filter.get('text')
export const selectAllData = createSelector(
allData,
(data) => data
)
export const selectAllDataFiltered = createSelector(
[ selectAllData, filterText ],
(data, text) => {
return data.filter(item => {
return item.name === text
})
}
)
export const selectWithValue = createSelector(
[ selectAllDataFiltered ],
(data, myValue) => {
console.log(myValue)
return data
}
)
let data = selectWithValue(state, 'myValue')
Run Code Online (Sandbox Code Playgroud)
console.log(myValue) 回报 undefined
我已经使用了面向对象的编程实践已有25年了,并试图在过去的5年中转向函数式编程,但是当我尝试做一些复杂的事情时,我的脑子总是转向OOP,特别是现在ES6支持体面的OOP语法,这是我构建东西的自然方式.
我现在正在学习Redux并且我理解(参见如何将方法放在Redux状态的对象上?)将类实例放入reducers中是不行的; 并且在普通减速器状态之上计算的推荐方法是使用选择器(例如,通过重新选择).而且,当然,阵营建议过遗传组合物(https://facebook.github.io/react/docs/composition-vs-inheritance.html,阵营终极版接力类).
但React/Redux生态系统中是否存在具有方法和继承的类对象的任何位置?
我想,为了回答我自己的问题,OOP类鼓励在同一个地方添加数据属性和操作,这对于可读性很好,但不适合纯函数和不可变数据.
如果我打算使用OOP,我是否需要放弃让我的实例持续并保持状态任何时间的想法?就像,每次我想使用一个,我会从商店数据中实例化它,使用我想要的任何方法,然后扔掉它?这可能会消除使用OOP类的很多动力.但如果我保留实例,我会头疼让他们与商店保持同步.
那么,当我试图使用方法并且在我试图使用继承时总是使用合成时,总是使用选择器的答案是什么?具体来说,我的意思是存储和操作Redux存储中保存的数据以用于React组件.如果是这样,它应该放在哪里?连接到选择器?像我建议的那样立即丢弃吗?
为了清楚起见,添加我的用例:我的数据基本上是一个巨大的图形:许多对象具有许多属性和对象之间的大量关系.它只读,但很复杂.我的对象被称为"概念".
在做(可能是愚蠢的)迁移到Redux的决定之前,我使用类来构造和表示概念,概念集和概念之间的关系.我的类包括用于获取概念集的异步api逻辑,有关每个概念的信息,以及与每个概念相关的其他概念的信息.如果用户选择向下钻取,则类将递归地获取并实例化新的概念集.Redux文档推荐了嵌套数据的平面,规范化结构(http://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html),这对于存储来说可能是明智的,但我的OOP模型很适合遍历部分图和东西.我很难使用可能涉及嵌套的选择器和不可变状态,可能包含循环,或者需要对更多数据进行异步调用.
我成功地使用https://redux-observable.js.org/作为api的东西.
也许@Sulthan的答案是正确的:我应该随意在我的Redux应用程序中使用OOP技术.但它似乎仍然很奇怪.我不能保留我的对象,因为如果存储更改(例如,更多数据被提取),我的对象可能会变得陈旧.如果我的对象是嵌套的,但我的存储是规范化的,那么当我需要它时,我会实例化它们(来自选择器),并确保不要让它们保持在...
我想创建一个带有memoization的选择器,使用基于某些ownProps的重新选择mapStateToProps.
我用来redux-toolkit生成选择器。我想在我自己的带有参数的自定义选择器中使用它们reselect。但我不知道如何输入我的选择器的返回类型?
const selectOrganizationName = (id: string): ??? =>
createSelector(
[(state: RootState) => organizationSelectors.selectById(state, id)],
organization => organization.name
);
export default selectOrganizationName;
Run Code Online (Sandbox Code Playgroud)
Missing return type on function.eslint@typescript-eslint/explicit-module-boundary-types
Run Code Online (Sandbox Code Playgroud) 我有一个选择器:
const someSelector = createSelector(
getUserIdsSelector,
(ids) => ids.map((id) => yetAnotherSelector(store, id),
); // ^^^^^ (yetAnotherSelector expects 2 args)
Run Code Online (Sandbox Code Playgroud)
这yetAnotherSelector是另一个选择器,它接受用户id - id并返回一些数据.
但是,既然如此createSelector,我就无法访问它(我不希望它作为一个函数,因为memoization不会工作).
有办法在某种程度上访问商店createSelector吗?或者有没有其他方法来处理它?
我有一个功能:
const someFunc = (store, id) => {
const data = userSelector(store, id);
// ^^^^^^^^^^^^ global selector
return data.map((user) => extendUserDataSelector(store, user));
// ^^^^^^^^^^^^^^^^^^^^ selector
}
Run Code Online (Sandbox Code Playgroud)
这样的功能正在杀死我的应用程序,导致所有内容重新渲染并让我疯狂.帮助赞赏.
我做了一些基本的自定义memoization:
import { isEqual } from 'lodash';
const memoizer = {};
const someFunc = (store, id) => { …Run Code Online (Sandbox Code Playgroud) 我使用重新选择来获得我的redux状态的一部分.我有一个州的对象列表.我的创建选择器的一个子选择器是此列表的过滤器功能:
state => state.list.filter(filterFunction)
Run Code Online (Sandbox Code Playgroud)
所以我把它传递给我的createSelector:
createSelector(
state => state.list.filter(filterFunction),
(subsetOfObjects) => subsetOfObjects.map(doSomething)
);
Run Code Online (Sandbox Code Playgroud)
此过滤器函数返回列表中我的对象的子集.因此,如果列表更改,则重新选择始终返回新对象,即使子集未更改,因为列表不相同(完全正确).
如果对象或过滤列表有变化,是否有可能只获得一个新对象?
我遇到了一个例子,mapStateToProps函数正在使用memoization.我只是想知道如何将"state"参数传递给memoized选择器.在查看重新选择以及redux的文档之后,似乎mapStateToProps可以返回一个接受状态作为其参数的函数,而连接装饰器可能是将状态传递给它但不确定的.有人可以解释一下吗?
视图/曲目列表/ index.js
const mapStateToProps = createSelector(
getBrowserMedia,
getPlayerIsPlaying,
getPlayerTrackId,
getCurrentTracklist,
getTracksForCurrentTracklist,
(media, isPlaying, playerTrackId, tracklist, tracks) => ({
displayLoadingIndicator: tracklist.isPending || tracklist.hasNextPage,
isMediaLarge: !!media.large,
isPlaying,
pause: audio.pause,
pauseInfiniteScroll: tracklist.isPending || !tracklist.hasNextPage,
play: audio.play,
selectedTrackId: playerTrackId,
tracklistId: tracklist.id,
tracks
})
);
export default connect(
mapStateToProps,
mapDispatchToProps
)(Tracklist);
Run Code Online (Sandbox Code Playgroud)
芯/ tracklists/selectors.js
export function getCurrentTracklist(state) {
// console.log(state);
let tracklists = getTracklists(state);
return tracklists.get(tracklists.get('currentTracklistId'));
}
export const getTracksForCurrentTracklist = createSelector(
getCurrentPage,
getCurrentTrackIds,
getTracks,
(currentPage, trackIds, tracks) => {
return trackIds
.slice(0, currentPage * …Run Code Online (Sandbox Code Playgroud) 我有一个返回数组的选择器.数组中的元素本身具有派生数据.我基本上需要一个递归memoization选择器,它返回一个由派生元素组成的派生数组.
我目前的尝试是:
export const selectEntitesWithAssetBuffers = createSelector(
[selectSceneEntities, getAssets],
(entities, loadedAssets) => {
return entities.map((entity) => {
entity.buffers = entity.assets.map((assetName) => {
return loadedAssets[assetName].arrayBuffer;
})
return entity;
})
}
)
Run Code Online (Sandbox Code Playgroud)
我在这里的担忧是随时entities或loadedAssets改变这将重新计算整个列表.我期待设置的东西就像是一个selectEntityWithBuffer传递给它的东西entities.map.理想情况下,我希望这只在entity.assets数组更改时重新计算.
出于记忆/性能考虑,使用useSelector with ShallowEqual. 使用“Reselect/createSelector”选项对性能优化会有更多好处吗?或者两个选项是相同的?
大多数选择器都会将数据作为 JSON 数组对象。
在编写新的选择器之前,想考虑性能/记忆的好处。
reselect ×10
reactjs ×8
redux ×8
javascript ×5
react-redux ×3
ecmascript-6 ×1
oop ×1
typescript ×1