- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
阅读之前:
这不是代码不工作的问题,而是架构的问题。此外,我目前没有使用 ReactRedux 库,因为我首先尝试了解这些部分如何在此测试应用程序中独立工作。它尽可能短,但不幸的是仍然很长,请耐心等待
简短介绍
我有一组 Bottle
模型。使用伪代码,一个瓶子是这样定义的:
class Bottle{
//members
filledLiters
filledLitersCapacity
otherMember1
otherMember2
//functions
toPostableObject(){
//removes functions by running JSON.
var cloneObj = JSON.parse(JSON.stringify(this));
//removes all members we dont want to post
delete cloneObj["otherMember1"];
}
//other functions
}
我还有一个显示所有 Bottle 项目的 React 组件。该组件还需要存储所有 Bottle 项目的先前状态(它用于动画,请忽略它)。
Redux 用法
我需要使用像这样的辅助类对一些 Bottle 项目执行复杂的操作:
var updated_bottles = BottleHandler.performOperationsOnBottles(bottleIds)
mainStore.dispatch({type:"UPDATED_BOTTLES",updated_bottles:updated_bottles})
我不想为每个操作更新商店,因为我希望商店在最后一次全部更新。因此我的 BottleReducer 看起来像这样:
var nextState = Object.assign({}, currentState);
nextState.bottles = action.updated_bottles
其中 action.updated_bottles 是执行操作后瓶子的最终状态。
问题
尽管一切正常,但我怀疑这是接近我的架构的“错误心态”。原因之一是为了避免在执行操作时保留对瓶子对象的引用并改变状态,我必须做这件丑陋的事情:
var bottlesCloneArray = mainStore.getState().
bottleReducer.bottles.map(
a => {
var l = Object.assign({}, a);
Object.setPrototypeOf( l, Character.prototype );
return l
}
);
这是因为我需要一个克隆的对象数组,这些对象仍保留其原始功能(意味着它们是该类的实际实例克隆)
如果您能指出我逻辑中的缺陷,我将不胜感激。
P.S:我需要保留类实例的“深度克隆”的原因是,我可以在我的 React 组件中保留瓶子的先前状态,以便在更新时在两种状态之间进行动画处理渲染发生。
最佳答案
在处理 redux 架构时,将序列化和不变性放在每个决策的最前沿是非常有用的,一开始这可能很困难,尤其是当您非常习惯 OOP 时
由于商店的状态只是一个 JS 对象,因此可能很想用它来跟踪更复杂的模型类的 JS 实例,但应该更像一个数据库,您可以在其中序列化模型的表示以不可变的方式进出它。
以最原始的形式存储你的瓶子的数据表示使得诸如本地存储的持久化和商店的再水化等更高级的应用程序成为可能,然后可以允许服务器端渲染和可能的离线使用,但更重要的是它使它变得更您的应用程序中正在发生和发生的变化更加可预测和明显。
我见过的大多数 redux 应用程序(包括我的)都沿用了完全取消模型类的功能路线,并直接在数据上直接在 reducer 中执行操作 - 可能在此过程中使用助手。这样做的缺点是它会导致大型复杂的 reducer 缺乏一些上下文。
但是,如果您希望将此类助手封装到 Bottle 类中,则有一个完全合理的中间立场,但您需要根据案例类来考虑,它可以是从数据形式创建并序列化回数据形式,并且如果对其进行操作则不可变
让我们看看这对您的 Bottle 有何作用( typescript 注释以帮助显示发生了什么)
瓶箱类
interface IBottle {
name: string,
filledLitres: number
capacity: number
}
class Bottle implements IBottle {
// deserialisable
static fromJSON(json: IBottle): Bottle {
return new Bottle(json.name, json.filledLitres, json.capacity)
}
constructor(public readonly name: string,
public readonly filledLitres: number,
public readonly capacity: number) {}
// can still encapuslate computed properties so that is not needed to be done done manually in the views
get nameAndSize() {
return `${this.name}: ${this.capacity} Litres`
}
// note that operations are immutable, they return a new instance with the new state
fill(litres: number): Bottle {
return new Bottle(this.name, Math.min(this.filledLitres + litres, this.capacity), this.capacity)
}
drink(litres: number): Bottle {
return new Bottle(this.name, Math.max(this.filledLitres - litres, 0), this.capacity)
}
// serialisable
toJSON(): IBottle {
return {
name: this.name,
filledLitres: this.filledLitres,
capacity: this.capacity
}
}
// instances can be considered equal if properties are the same, as all are immutable
equals(bottle: Bottle): boolean {
return bottle.name === this.name &&
bottle.filledLitres === this.filledLitres &&
bottle.capacity === this.capacity
}
// cloning is easy as it is immutable
copy(): Bottle {
return new Bottle(this.name, this.filledLitres, this.capacity)
}
}
存储状态注意它包含一个数据表示而不是类实例的数组
interface IBottleStore {
bottles: Array<IBottle>
}
瓶子选择器在这里,我们使用选择器从商店中提取数据,并将其转换为类实例,您可以将这些实例作为 Prop 传递给 React 组件。如果使用像 reselect
这样的库,这个结果将被内存,所以你的实例引用将保持不变,直到它们在商店中的基础数据发生变化。这对于使用 PureComponent 优化 React 很重要,它仅通过引用比较 props。
const bottlesSelector = (state: IBottleStore): Array<Bottle> => state.bottles.map(v => Bottle.fromJSON(v))
瓶子 reducer 在你的 reducer 中,你可以使用 Bottle 类作为执行操作的助手,而不是直接在 reducer 中对数据本身做所有事情
interface IDrinkAction {
type: 'drink'
name: string
litres: number
}
const bottlesReducer = (state: Array<IBottle>, action: IDrinkAction): Array<IBottle> => {
switch(action.type) {
case 'drink':
// immutably create an array of class instances from current state
return state.map(v => Bottle.fromJSON(v))
// find the correct bottle and drink from it (drink returns a new instance of Bottle so is immutable)
.map((b: Bottle): Bottle => b.name === action.name ? b.drink(action.litres) : b)
// serialise back to date form to put back in the store
.map((b: Bottle): IBottle => b.toJSON())
default:
return state
}
}
虽然这个 drink
/fill
示例相当简单,并且可以直接在 reducer 中的数据上直接在尽可能多的行中轻松完成,但它说明了使用用案例类来表示更真实世界的数据仍然可以做到,并且可以使它更容易理解并使代码更有条理,而不是拥有一个巨大的 reducer 和手动计算 View 中的属性,作为奖励,Bottle 类也很容易可测试。
通过在整个过程中保持不变,如果设计正确,您的 React 类的先前状态将继续保留对您之前的瓶子的引用(处于它们自己的先前状态),因此无需以某种方式跟踪您自己进行动画等
关于javascript - React 和 Redux 架构问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47469506/
我一直在尝试将 redux sagas 和 redux 工具包引入我的项目。我目前遇到的问题是 watcher saga 没有捕捉到 takeEvery 中的调度 Action 。效果并运行处理程序。
我需要使用 deep-freeze 库来深度卡住 react redux 应用程序中的整个 redux 状态,以检查状态是否有任何变化。我应该如何使用 deep-freeze 和 React redu
这是一个关于 Redux js 中状态的问题。我在该州有一个数组列表: { list: list } 根据 Redux 文档,我不应该修改 reducer 中的状态。我想在列表中添加一个新项目。我
我正在构建一个应用程序,在用户向下滚动时执行操作。如果我可以在用户再次向上滚动时撤消这些操作,基本上将滚动变成浏览操作时间线的一种方式,那就太好了。 Redux 中是否有内置的方法来做到这一点?或者我
从我从 Dan Abramov 的蛋头视频“javascript-redux-colocating-selectors-with-reducers”和他的一些推文中了解到,使用选择器将状态映射到 Pr
尝试使用 redux saga 运行 reduxdevtools: 收到此错误: Error Before running a Saga, you must mount the Saga middle
Redux 工具包文档提到在多个 reducer 中使用操作(或者更确切地说是操作类型) First, Redux action types are not meant to be exclusive
Redux 将调度状态更改的操作。 redux 中 Action 类型的命名约定是什么? 最佳答案 社区中有一些约定,我将在这里列出我知道并认为有用的约定: 最常见的约定是 将 Action 类型(“
使用 Redux Toolkit 可以吗,即使我只在其中创建 Slice 并通过 Redux Saga 解决中间件问题? 或者在这种情况下,最佳实践是使用 Redux Saga + raw Redux
Redux 如何处理深度嵌套的叶子模型变更?意思是,我正在从叶子一直发送到它的 reducer 句柄的更改事件,并且我不想将更改事件广播到整个树。 最佳答案 在 Redux 中,所有操作总是被分派(d
redux 使用什么类型的数据结构来使数据在 Angular 和 React.js 中持久化?我假设它使用持久数据结构。 最佳答案 Redux 是一种用于管理状态的架构。它不使用任何数据结构。它保留您
我们正在计划一个 Electron 应用程序,并且我们正在考虑 Redux。该应用程序将具有巨大 状态,可能会从数十个或数百个文件中读取数据。在做一些了解 Redux 的研究时,我发现 reducer
我不想添加属性 sections: []到我的对象 formOpen在 reducer 中,我收到我的对象 formOpen从我的服务器和其他属性,我想添加这个,我该怎么做? 谢谢 import {
我使用 redux-saga 的主要原因之一是它进行异步函数调用的可测试性。我的困境是,当我使用不属于我的 redux 存储的有状态对象进行编程时,使用 sagas 进行编程变得非常尴尬。是否有使用非
我是 redux 的新手,所以我有几个问题希望得到解答。如果您能解释一些有关构建 redux 架构的内容,那就太好了。 此时我使用 Flutter_Redux 包 ( https://pub.dart
我正在使用 React + Flux。我们的团队正计划从 flux 转向 redux。来自 Flux 世界的我对 Redux 感到非常困惑。在 flux 控制流中很简单,从组件 -> 操作 -> 存储
这个问题与过去不同,这就是为什么。这个问题是什么时候。由于两者本身都是很好的框架,所以问题是我什么时候应该使用 thunk 而不是 saga。因为我的一位 friend 一直坚持让我在我们的应用程序中
我搜索了高低,但找不到明确的答案。 我已经设法绕开 Redux 的机制,但是当我谈到 API 调用和异步操作创建者时,我被 Promises 上下文中的中间件所困。 你能帮我把乱七八糟的东西弄好吗?
我正在使用 redux-saga 但遇到了一个问题:redux-auth-wrapper 需要 redux-thunk进行重定向,所以我只是在我的商店中添加了 thunk: import {creat
问题(tl;博士) 我们如何创建 custom redux-orm reducer与 redux-toolkit的createSlice ? 有没有比这个问题中提供的尝试更简单、推荐、更优雅或只是其他
我是一名优秀的程序员,十分优秀!