我正在将一个现有的应用程序移植到Flux,我对一个主题感到有些困惑.假设我有几个返回两级或三级嵌套对象的API端点.
例如,GET /articles可以返回架构的JSON响应
articles: article*
article: {
author: user,
likers: user*
primary_collection: collection?
collections: collection*
}
collection: {
curator: user
}
Run Code Online (Sandbox Code Playgroud)
如您所见,不同级别的嵌套有各种各样的用户:
articles[i].authorarticles[i].likers[i]articles[i].primaryCollection.curatorarticles[i].collections[i].curator如果我想在UserStore任何时候获取文章时使用新数据进行更新,我必须编写一个怪异的方法来检查文章API响应中的所有嵌套实体.此外,会有很多重复,因为还有其他API端点具有不同的模式,有时文章嵌入在用户内(例如GET /user/published).
Flux商店是否有更清晰的方法从所有API响应中提取嵌套实体?
在上一个问题中,我询问谁负责在Flux应用程序中向服务器发送更新.人们告诉我,行动应该这样做.所以我假设从服务器获取数据也是如此; 您有一个FetchData操作,它获取数据并调度要保留的商店的数据.但在这种情况下,缓存逻辑将如何工作?
我想我必须存储最后一次请求列表,并且StreamsStore中的列表的TTL和fetchStreams操作将检索TTL和上次获取时间以确定是否需要查询服务器.
这是正确的方法吗?在商店和动作之间传播缓存逻辑对我来说似乎很奇怪,但我想不出更好的方法.
我的有限数量的测试似乎表明答案是否定的.我正在为一个父级React组件(也就是一个控制器视图)编写一个单元测试,它依赖于一个商店.但是,Jest没有为商店提供自动模拟,因为文档建议它应该,而是调用真正的实现.
这是一个bug还是设计?如果是后者,单元测试反应组件是不可取的?
编辑1
在测试CommonJs模块时,自动锁定工作正常; 它只是不适用于反应组件.
我在reactjs-flux编写一个简单的应用程序,一切正常,除了我收到来自reactjs的警告,告诉我我在未安装的组件上调用setState.
我已经弄明白这是因为没有从商店中删除组件被挂钩的changelisteners componentWillUnmount.我知道这一点,因为当我打开监听器列表时,Eventemitter我会看到应该被销毁的监听器,并且当我多次挂载/卸载相同的组件时,列表会变大.
我从我的BaseStore粘贴代码:
import Constants from '../core/Constants';
import {EventEmitter} from 'events';
class BaseStore extends EventEmitter {
// Allow Controller-View to register itself with store
addChangeListener(callback) {
this.on(Constants.CHANGE_EVENT, callback);
}
removeChangeListener(callback) {
this.removeListener(Constants.CHANGE_EVENT, callback);
}
// triggers change listener above, firing controller-view callback
emitChange() {
this.emit(Constants.CHANGE_EVENT);
}
}
export default BaseStore;
Run Code Online (Sandbox Code Playgroud)
我从遇到此错误的组件中粘贴相关代码(但它适用于所有组件):
@AuthenticatedComponent
class ProductsPage extends React.Component {
static propTypes = {
accessToken: PropTypes.string
};
constructor() {
super();
this._productBatch;
this._productBatchesNum;
this._activeProductBatch;
this._productBlacklist;
this._searchById;
this._searchingById;
this.state = this._getStateFromStore(); …Run Code Online (Sandbox Code Playgroud) 我知道我需要一个emit.change()调度员,让所有组件都知道商店内部发生了变化.但我不明白为什么我需要调度操作而不是直接从操作中调用存储,
我为什么要这样做:
var Dispatcher = require('dispatcher');
var MyActions = {
addItem: function(item){
Dispatcher.dispatch({
action: 'ADD_ITEM',
payload: item
})
}
}
Run Code Online (Sandbox Code Playgroud)
而不是这个:
var MyStore = require('mystore');
var MyActions = {
addItem: function(item){
MyStore.addItem(item);
}
}
Run Code Online (Sandbox Code Playgroud)
是的情况下,多个卖场听同样的事件,例如,当StoreA和StoreB听ADD_ITEM呢?
处理深节点中状态更改的最佳方法是什么,这也需要由父节点处理.这是我的情况:
<Table>
<Row prop={user1}>
<Column prop={user1_col1} />
<Column prop={user1_col2} />
</Row>
<Row prop={user2}>
<Column prop={user2_col1} />
<Column prop={user2_col2} />
</Row>
<TableFooter>
<FooterColumn prop={sum1} />
<FooterColumn prop={sum2} />
</TableFooter>
</Table>Run Code Online (Sandbox Code Playgroud)
每当有人在列属性中更改任何内容时,我只需要在该Column组件中维护此值的状态.但是,我现在想要FooterColumn组件中的这些值的总和.实现这一目标的最佳方法是什么?
如果我要放弃状态改变,我必须将状态保存在多个地方,然后将其传递下去,这是一项繁琐的工作.是最好使用EventEmitters还是我错过了什么?
我正在尝试使用webpack构建一个应用程序,但发现了一个问题.应用程序的堆栈是React + Flux架构(可用ES6语法),对于构建系统,我使用的是webpack.我试图解决的问题是应用程序的构建系统的想法,它被分解为核心模块和位于子目录核心内部的子模块.核心系统应提供基本功能(如调度程序,基本Flux操作和核心视图模块),插件应能够导入核心功能以扩展应用程序.
当前的构建解决方案允许我构建一个应用程序,但我遇到了可能重复的模块的问题.我创建了位于核心模块中的插件存储,以及允许在核心内部注册不同模块的registerPlugin操作.
核心模块具有index.js文件中插件的入口点,我在其中导出可恢复的组件和操作(也用于注册插件).
// core index.js
export * as AppDispatcher from './src/dispatcher/AppDispatcher';
export BaseModel from './src/models/BaseModel';
export registerPlugin from './src/actions/registerPlugin';
// etc..
Run Code Online (Sandbox Code Playgroud)
该文件随每个插件一起导入,并允许我访问这些模块.
// bootstrap plugin / entry point for plugin webpack
import {registerPlugin} from 'core-module';
// plugin index.js
require('./dist/plugin');
Run Code Online (Sandbox Code Playgroud)
此外,每个插件都公开index.js文件,该文件返回核心的捆绑产品.然后核心只是抓取该文件并在引导过程中导入它.
// bootstrap app / entry point for webpack
import 'plugins/plugin-1';
import 'plugins/plugin-2';
...
Run Code Online (Sandbox Code Playgroud)
一切都运作良好,但后来我发现(可能)依赖重复的问题.当我尝试从核心调试代码时,似乎插入了动作的插件存储,但是每个存储都是不同的实例,所以基本上当我在核心模块中监听存储更改时,我看不到这种变化(因为一些不同的商店已经改变,可能有两个调度员在这里,也许两个行动......).
这是循环依赖的问题吗?有没有办法配置webpack,以便它不会复制该操作?
另外值得一提的是,每个插件都有自己的webpack配置,允许我为插件创建bundle,并且该bundle正被核心模块抓取,然后webpack for core module正在为整个应用程序创建bundle.
我有一个范围问题.我可以在构造函数中调用console.log this.props.routeParams.key.但是当在构造函数之外,在filterList函数中,我得到错误"未捕获的TypeError:无法读取未定义的属性'道具'".我的范围问题是什么?为什么它可以从构造函数中读取,而不是从filterList函数中读取?
我正在使用React Router + Flux + React.
import AltContainer from 'alt-container';
import React from 'react';
import { Link } from 'react-router';
import Blogger from './Blogger'
import List from './List'
const rootURL = 'https://incandescent-fire-6143.firebaseio.com/';
import BlogStore from '../stores/BlogStore'
import BlogActions from '../actions/BlogActions';
export default class BlogShow extends React.Component {
constructor(props) {
super(props);
{console.log(this.props.routeParams.key)}
}
filterList(key) {
if (this.props.routeParams.key===key){
return Blogstore.state.blog
}
}
render() {
{Object.keys(BlogStore.state.blog).map(this.filterList)}
}
}
Run Code Online (Sandbox Code Playgroud) 试图了解React-Redux,我觉得不寻常的是,当状态的任何一部分发生变化时,我的所有组件都会获得新的道具.这是设计还是我做错了?
示例App
class App extends React.Component {
render(){return (
<div>
<Navbar data={this.props.navbar} />
<Content data={this.props.content} />
</div>);
}
}
select (state) => ({ navbar:state.navbar, content:state.content});
export default connect(select)(App);
Run Code Online (Sandbox Code Playgroud)
组件
export const NavbarForm = props => {
console.log('RENDERING with props--->',props);
return (<h1>NAV {props.data.val}</h1>);
};
export const ContentForm = props => {
console.log('RENDERING CONTENT with props--->',props);
return (<h1>CONTENT {props.data.val}</h1>);
};
////////INDEX.js//////
const placeholderReducer = (state={val:0},action)=>{
//will update val to current time if action start with test/;
if(action.type.indexOf('TEST/') === 0)return {val:Date.now();}
return state; …Run Code Online (Sandbox Code Playgroud) 我正在学习React + Redux,我不明白做动画的正确方法.让我们举例说明:
例如,我有一个列表,我想删除点击项目.如果我没有动画效果那就非常容易:REMOVE_ITEM点击时调度动作,reducer从商店中删除项目并对重新渲染html做出反应.
让我们添加一个在点击时删除订单项的动画.因此,当用户点击某个项目时,我想要运行删除订单项的奇特效果...... 如何?我可以想到几种方法:
1)点击我调度REMOVE_ITEM动作,然后reducer标记一个项目,如goingToBeDeletedStore,然后反应渲染该元素与一个类,.fancy-dissolve-animation我运行一个计时器来调度第二个动作REMOVE_ITEM_COMPLETED.我不喜欢这个想法,因为它仍然不清楚如何在这里添加JS动画(例如,使用TweenMax),并且我运行JS计时器以在CSS动画结束时重新渲染.听起来不太好.
2)我ITEM_REMOVE_PROGRESS以~30ms的间隔调度动作,并且store保存一些表示当前动画状态的"值".我也不喜欢它,因为它需要我复制商店约120次~2秒的动画(比方说,我想要平滑的60 fps动画),这只是浪费内存.
3)制作动画并REMOVE_ITEM仅在动画结束后发送.这是我能想到的最合适的方式,但我仍然想在用户做出动作后立即更改存储.例如,动画可能需要超过几秒钟,并且REMOVE_ITEM可能与后端同步 - 没有理由等待动画完成后端API调用.
感谢阅读 - 任何建议?
flux ×10
reactjs ×8
reactjs-flux ×3
javascript ×2
react-redux ×2
redux ×2
action ×1
animation ×1
architecture ×1
caching ×1
cqrs ×1
ecmascript-6 ×1
jestjs ×1
json ×1
nested ×1
react-router ×1
webpack ×1