我正在为React应用程序编写测试,该应用程序使用Fluxxor来提供事件调度程序.做这项工作需要告诉Jest不要模拟内部使用的几个模块,并由Node本身提供.
这意味着我不能只将它们添加到unmockedModulePathPatterns配置键,而是必须使用这样的代码:
[ 'util', 'events' ].forEach(function (module) {
jest.setMock(module, require.requireActual(module));
});
Run Code Online (Sandbox Code Playgroud)
但是,我找不到任何有用的东西.我有一个setupEnvScriptFile设置了几个我在几乎所有测试中使用的全局变量,但是该jest对象在该上下文中似乎不可用,所以我不能只在那里设置模拟.
作为一个hacky权宜之计,我把上面的代码包装在一个函数中,我在describe测试Fluxxor商店的任何块的开头调用它,但它远非理想.
我有自己的方法如何使用React并构建我自己的框架,受Om的启发.我正在实现一些类似于Flux架构的东西,其中的商店可以在某些事件上自行更新.
我不确定理解为什么在Flux架构中我们需要存储依赖性?
对于给定的有界环境,商店不应该是自包含数据持有者,就像我们使用CQRS架构一样?
在一个事件系统中,2个CQRS组件最终可能保留相同的数据.我们是否表达商店依赖关系以避免在商店中存储重复数据?
有人可以提出一些非常具体的用例,其中需要存储依赖关系并且问题难以以任何其他方式解决吗?我找不到任何自己.
如何从文本输入更新redux的状态?
我正在尝试用文本输入做一个非常简单的"Hello World".当有人输入文本输入时,它应该更新我的商店的"searchTerm"值.
我无法弄清楚这些事情:1.我怎样才能将输入的值传递给它的"onChange"处理程序?2."搜索"操作似乎被正确调用,但我的reducer函数从未使用过(没有console.log).
SearchForm.js(组件)
import React, {Component, PropTypes} from 'react';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {search} from 'redux/modules/search-term';
@connect(
null,
dispatch => bindActionCreators({ search }, dispatch)
)
export default class SearchForm extends Component {
static propTypes = {
search: PropTypes.func.isRequired,
}
render() {
return (
<input type="text" placeholder="Search" onChange={search} />
);
}
}
Run Code Online (Sandbox Code Playgroud)
search-term.js(动作和减速器)
const SEARCH = 'redux-example/repo-filter/SEARCH';
const initialState = {
searchTerm: null
};
export default function reducer(state = initialState, action = …Run Code Online (Sandbox Code Playgroud) 所以我使用Backbone的路由器有一个简单的React/Flux应用程序.我有一个用户创建对象的情况,并且路径从更新/object/new到/object/:id.但是,不需要重新呈现页面,因为组件是相同的,并且由于ajax-create调用返回后关联的存储更新,它会更新自身.
目前,我刚刚修补了路由器以公开一个只更新网址的方法,并且实际上没有点击路由特定的方法.这感觉很麻烦,并没有真正解决需要添加/删除某些组件(即小部件)的情况(至少它消除了知道哪些组件需要从路由器中呈现出来的责任),但是主要的UI不需要重新渲染.
所以这给我留下了三个问题:
Flux模型要求在视图中启动状态的任何更改,触发通过调度程序工作的操作并将商店传播回监听视图.

这一切都很好,花花公子.但是如果我需要在状态发生特定变化后执行一些DOM操作呢?在现实世界的应用程序中,我们有时必须使用它,你知道,称为jQuery插件的遗物(还记得吗?)
例如,我需要初始化一个jQuery视频播放器,点菜$('#videoContainer').initPlayer(streamURL),一个Ajax请求检索后 streamURL.请奉献一点时间来弄清楚如何,你会做到这一点与流量/反应,前阅读).
在视图部分,我可能会使用componentWillReceiveProps:
var jsVideoPlayer = React.createClass({
componentWillReceiveProps: function(nextProps) {
$(this.refs.videoContainer.getDOMNode()).initPlayer(nextProps.streamURL);
},
render: function() {
return (
<div ref="videoContainer">
</div>
);
}
});
Run Code Online (Sandbox Code Playgroud)
但是在这里,玩家每次状态更新时都会被初始化.这肯定会打破我们的视频播放器.因此,在实际执行任何操作之前,请检查URL是否已更改:
componentWillReceiveProps: function(nextProps) {
if (nextProps.streamURL && nextProps.streamURL !== this.streamURL) {
this.streamURL = nextProps.streamURL;
$(this.refs.videoContainer.getDOMNode()).initPlayer(nextProps.streamURL);
}
},
Run Code Online (Sandbox Code Playgroud)
容易,对吗?但是大局呢?如果我们增加更多的功能和UI元素,那么我们可以扩大和扩展 - 这可能会导致更多自定义验证代码在视图中显示来自商店的内容.即使在一个完美的应用程序中,每个商店都拥有自己的域名,并且所有内容都在设计模式中一尘不染地布置在一个值得专注的宗教追随者的水平上,我们仍然必须在视图中使用越来越多的逻辑,因为应用程序会扩展.
在我们的团队中,我认为这个逻辑应该真正进入一个适合Flux模型的ControllerView--但其他人都认为这是框架应该关注的事情.我们是Flux/React的新手,并且无法想出如何让框架为我们做到这一点.
我正试图找出通过我的路线传递数据的最佳方法.我知道我可以使用params但是某些类型的数据不属于params.
例如:我有一个显示应用程序列表的索引页面.每个应用程序旁边都有一个按钮,它将引导您进入该应用程序的视图.
我想将应用程序本身传递给Application处理程序.但是,通过params传递整个应用程序是没有意义的.虽然将应用程序标识符传递给params(即:id或:name)确实有意义
所以我认为我应该这样做的方法是将应用程序标识符传递给params,然后在Application组件中搜索我的ApplicationStore以获取给定标识符的相应应用程序.
但是,通过应用程序本身会不会更容易,更快?有没有办法做到这一点.有没有理由不这样做?
这是一些代码:
<Link to="showApplication" params={{name: application.name}}>View</Link>
要么
<Link to="showApplication" params={{application: application}}>View</Link>
提前致谢!
我一直在和Flux合作,我真的很享受,但我有一点我无法想出什么是最好的解决方案.我创建了一个处理订单列表的应用程序,列表中的每个订单都分为不同的组件,这些组件可以具有读取/编辑模式(基本上变成小形式)并触发更新(订单中的产品列表,发货成本等).

一切正常,除非我必须在订单更新时处理来自服务器的异常(例如,用户更改了其中一个产品数量但库存不足,我希望组件显示该特定产品的表单特定的顺序显示内联消息,所以我必须将错误消息传递给一个非常特定的组件.该列表最多可以有50个订单,每个订单由4-5个组件组成,可以触发更新,所以我可以有大约200个可能对ORDER_UPDATE_FAILED操作感兴趣的组件.
我能想到的唯一两个选择是:
异步进行更新并创建ORDER_UPDATE_FAILED,并且Store具有将转换中的变换放入可由Order Part Component识别的对象中的逻辑(考虑orderID + errorID).这将保持数据的单向循环和操作的异步,但感觉过于复杂和繁琐,并增加了一些问题:
a)如果错误存储在Store中,则组件必须在错误不再有效时通知存储,这可能无法始终执行).
b)如果用户在不改变值的情况下点击保存并且组件处于"加载状态",即使呼叫成功,订单也保持不变,因此没有退回以退出"加载状态".
有没有人找到更优雅的方法来解决这个问题?
我正在尝试在Flux-React中设置最基本的应用程序.它的唯一目标是触发一个Action,它通过Dispatcher发送到已经向Dispatcher注册的Store.将商店记录payload到控制台.
除了Store之外的所有东西都运行良好,但是一旦它命中AppDispatcher.register,Flux就会抛出以下错误:
Uncaught TypeError: Cannot set property 'ID_1' of undefined
Run Code Online (Sandbox Code Playgroud)
这是导致错误的文件的代码,但我已经把整个项目放在https://github.com/bengrunfeld/react-flux-dispatcher-error,你可以在src/js中找到有问题的文件/stores/AppStores.js
var AppDispatcher = require('../dispatcher/AppDispatcher');
var EventEmitter = require('events').EventEmitter;
var AppConstants = require('../constants/AppConstants');
var assign = require('object-assign');
var CHANGE_EVENT = 'change';
var AppStore = assign({}, EventEmitter.prototype, {
emitChange: function() {
this.emit(CHANGE_EVENT);
}
});
AppDispatcher.register(function(payload){
console.log(payload);
return true;
})
module.exports = AppStore;
Run Code Online (Sandbox Code Playgroud) 我正在React/Flux中构建一个Word Dojo克隆.游戏本质上是Boggle - 您通过单击网格中的相邻字母来创建单词:

我的React组件及其来源:
所有源代码都可以在这里查看.
它现在如何工作:
有一个GameStore,它包含一个二维javascript对象数组.对象具有'letter'字符串值和'active'布尔值.当用户单击一个字母时,会调度到GameStore,后者会更新该二维数组并发出Change事件.
GameBoard组件侦听该更改事件,然后重新渲染10个TileColumns,每个TileColumns渲染10个Tiles.GameBoard将商店的数据作为其状态的一部分,并且tile具有自己的字母/活动状态作为道具.
问题是更改1个字母会导致重新渲染所有100个图块.
shouldComponentUpdate
我尝试在Tile上使用shouldComponentUpdate来指定它只应在其"活动"值发生变化时才更新,但问题是this.props.active和nextProps.active都是相同的值:要么它们都是假的,或两者都是真的.
推迟对孩子们的责任
我的另一个想法是让每个Tile负责自己的更新,直接在tile上注册更改侦听器.我收到一个警告,我超过了监听器的数量,看起来好像100个更改监听器,所有触发每个字母更新的效率都会降低.虽然这只是Javascript,所以我们要避免一些DOM操作......
性能
我启动了Profiler,现在,在父母完成所有状态管理的情况下,它需要40ms才能在信件点击时重新渲染整个电路板.这还不错,但是当游戏变得更复杂时,我担心它会变得明显延迟.
需要帮助
具体来说,我正在寻找有关这种情况下最佳实践的建议(当你有嵌套的,迭代的组件时),如果shouldComponentUpdate 是解决方案,但我只是错误地使用它.
谢谢!
我正在使用react-native-router-flux为我的应用程序主导航.我需要设置一个嵌套路由器.我有一个地图组件,其侧栏有一个区域列表.当我单击一行时,我需要切换到具有属于该区域的细分列表的视图.我看了一些例子并试图弄明白.目前在控制台中没有错误,但侧边栏中没有显示任何内容.如果有更好的方法,请告诉我.谢谢!
Maprouter
export default class RootRouter extends Component {
render() {
return(
<Router hideNavBar={true}>
<Schema name="default" sceneConfig={Navigator.SceneConfigs.FloatFromRight}/>
<Route name="mapSurveyTerritories" wrapRouter={false} component={MapSurveyTerritories} initial={true}/>
<Route name="mapSubdivisions" wrapRouter={false} component={MapSubdivisions} />
</Router>
);
}
}
Map Component
BackAndroid.addEventListener('hardwareBackPress', function() {
Actions.pop();
return true;
});
export default class Map extends Component {
constructor(props) {
super(props);
this.state = {
region: Albuquerque,
};
}
render() {
const { region, markers,surveyTerritories,selectedMarket } = this.state;
return (
<View style={styles.container}>
<Navbar
title="Map"/>
<View style={styles.innerContainer}>
<MapView
style={styles.map}
initialRegion={region}
onLongPress={this.onPress.bind(this)}>
{markers.map(marker => …Run Code Online (Sandbox Code Playgroud) reactjs-flux ×10
reactjs ×9
javascript ×3
flux ×2
cqrs ×1
jestjs ×1
jquery ×1
om ×1
performance ×1
react-jsx ×1
react-native ×1
react-router ×1
redux ×1
unit-testing ×1
url-routing ×1