是否存在用于管理用户与各个组件交互的已建立模式,例如显示加载器微调器,在表单保存/加载时禁用输入字段等?
我发现自己在我的商店里做了以下事情,以保持组件与任何隐含状态分离:
function CampaignStore() {
EventEmitter.call(this);
AppDispatcher.register(payload => {
switch (payload.type) {
// [#1] ---------------v (main action)
case CampaignContants.SAVE:
// [#2] ------------------------v (prepare for the main action)
this.emit(CampaignContants.WILL_SAVE);
const data = payload.data;
if (data.id) {
// [#3] ---v (perform main action in store)
updateCampaign(payload.data).then(_ => {
// [#4] ------------------------v (after main action)
this.emit(CampaignContants.DID_SAVE, 0)
});
} else {
insertCampaign(payload.data).then(campaignId => this.emit(CampaignContants.DID_SAVE, campaignId));
}
break;
// ...
}
}
}
基本上,我只是发出一个事件,说某些动作即将发生,然后我执行动作(进行API调用等),然后在动作完成时发出另一个事件。
在组件内部,我可以订阅WILL_<action>
事件,渲染所有的微调器等,然后在DID_<action>
被触发时清理屏幕。虽然这似乎有效,但它确实感觉很漂亮和重复,以及超级凌乱(太多的状态只存在根据动作的位置调整UI(在WILL_<action>
和* DID_<action>
之间)。
// some component
var MyComponent = React.createClass({
getInitialState: function () {
return {
items: [],
loading: false,
saving: false,
checkingPasswordStrength: fase,
// ...
};
},
render: function(){
return (
<div>
{this.state.loading && (
<p>Loading...</p>
)}
{!this.state.loading && (
// Display component in not-loading state
)}
</div>
);
}
});
我认为你最好使用生命周期方法,如componentWillMount
,componentDidMount
,componentWillUpdate
和componentWillUnmount
。使用这些方法,您可以检查前一个/当前/下一个道具/状态(取决于方法)并对其做出响应。这样你的商店只处理你的状态,你的组件变得更纯净。
我们在这里发现了一个简单的装载容器组件。所以这样的事情:
const LoadingContainer = React.createClass({
getDefaultProps: function() {
return {isLoadedCheck:(res) => res.data!=null }
},
getInitialState: function() {
return {isLoaded:false, errors:[]}
},
componentDidMount: function() {
if(this.props.initialLoad) { this.props.initialLoad(); }
if(this.props.changeListener) { this.props.changeListener(this.onChange); }
},
onChange: function() {
let res = this.props.loadData();
this.setState({errors: res.errors, isLoaded: this.props.isLoadedCheck(res)});
},
render: function() {
if(!this.state.isLoaded) {
let errors = this.state.errors && (<div>{this.state.errors.length} errors</div>)
return (<div>{errors}<LoadingGraphic /> </div>)
}
return <div>{this.props.children}</div>
}
});
const Wrapper = React.createClass({
getDefaultProps: function() {
return {id:23}
},
render: function() {
let initialLoad = () => someActionCreator.getData(this.props.id);
let loadData = () => someStore.getData(this.props.id);
let changeListener = (fn) => someStore.onChange(fn);
return (<div><LoadingContainer initialLoad={initialLoad}
changeListener={changeListener}
loadData={loadData}
isLoadedCheck={(res) => res.someData != null}><SomeComponent id={this.props.id} /></LoadingContainer></div>)
}
});
虽然它增加了另一个无状态包装器,它提供了一种干净的方法来确保你的组件不只是加载到mount和一个公共地方来显示api反馈等等。并且有反应14这些纯粹的无状态包装器正在得到一点推动,随着性能的改进,我们发现它很好地扩展
这种模式可以帮助您获取单个组件来管理用户交互
var MyComponent = React.createClass({
getInitialState: function() {
return {
item: [],
loading: true,
};
},
componentDidMount: function() {
//Make your API calls here
var self = this;
$.ajax({
method: 'GET',
url: 'http://jsonplaceholder.typicode.com/posts/1',
success: function(data) {
if (self.isMounted()) {
self.setState({
item: data,
loading: false
});
}
}
});
},
render: function() {
var componentContent = null;
if (this.state.loading) {
componentContent = (<div className="loader"></div>);
} else {
componentContent = (
<div>
<h4>{this.state.item.title}</h4>
<p>{this.state.item.body}</p>
</div>
);
}
return componentContent;
}});