原文:Thinking Statefully
javascript
熟练掌握React的过程包含了如何解决特定问题的方法转变.这提醒我,这个学习过程有点像在路上不一样的方向开车. 第一次感觉这一点是,我真正访问土耳其和卡斯柯岛,他们的车都靠左行驶.在美国咱们是靠右行驶,因此要花很大的力气重编程. 一出机场就差点完蛋了.java
有意思的是,即便我已经能够在正常的直道上行驶,可是在不一样状况发生时,大脑仍然把他转换成了旧的习惯.react
转进停车场?习惯接管了,我开进了错误的车道.在停车标志车左转?仍是一样的问题.向右转?你认为我已经了解了一切,可是对于个人大脑,彻底没这回事.git
我讲这个故事是由于在学习React的时候,个人经历是相似的.我想其余人也有这样的经历.github
传递props到组件(最好把组件当作是函数),大脑也已习惯了. 看起来和HTML的工做差很少.编程
在简单实例中,往下传递数据,向上传递事件也很好理解.这就是回掉模式,在其余的地方也很常见.向按钮组件传递一个onClick
handler是至关普通.redux
可是若是须要Modal对话框.或者是提示Badge,要怎么操做?亦或者根据事件响应来对一个Icon进行动画操做?能够看到,这些都是命令式的,"事件驱动"的内容在声明式和状态时的React世界显得很不天然.数组
若是你有jQuery,Angular的经验或者其余框架的以经验,须要调用函数执行任务("过程式编程"),在React的领域里为了更为有效的工做就须要调整思惟模型.从实践中能够很快的完成这个转变-只须要给大脑一些新的实例或者"模式".框架
这里是一些实例函数
打开/关闭一个Accordion组件(手风琴组件)
旧有办法: 点击toggle按钮调用toggle
函数,从而打开或者关闭accordion.Accordion组件知道该怎么关闭或打开. state方法: Accordion要么是"open"状态,要么是"close"状态. 这个信息咱们做为一个标记(flag)存储在Accordion组件的父组件state上(不在Accordion上存储).以名为isOpen
的prop形式传递state信息,Accordion依据prop来进行渲染. 当isOpen
是true
时,渲染为打开,反之就关闭.
<Accordion isOpen={true}/>
// or
<Accordion isOpen={false}/>
复制代码
这个实例相对简单.但愿不要有什么认知负担. 最大的挑战是以声明式的React方法处理,打开/关闭的state是存储在Accordion组件以外,并以prop的形式传递的.
旧有办法: 点击按钮打开modal,点击按钮关闭. state方法: Modal是开仍是闭是一个状态,"open","state"二者居其一.因此state是"open",咱们就渲染组件.若是是"close",就不作渲染.此外,能够给Modal传递onClose
回调函数-经过这种方法,Modal组件的父组件决定了用户点击按钮时应该干什么
{this.state.isModalOpen && <Modal onClose={this.handleClose}/>} 复制代码
详细内容请看Modal Dialogs in React
旧有办法: 当一个事件发生时(例如一个错误),调用提示库的组件来显示popup,例如toast.error("Oh,no!")
state方法: 把提示做为一个state.有0个或者1个,或多个提示,保存在消息数组中. 在根组件处安置提醒组件. 传递state用于显示.你能够用不一样的方式来管理消息数组:
addNotification
prop,或者导入能够添加到全局单例对象的函数.在应用中,你可使用软件包来完成任务,例如react-redux-toastr
.可是概念很简单,因此能够根据你的需求本身编写.
假设你有一个有数字的badge用于显示登陆的用户,组件从prop获取这个数字.可是若是你想在组件数字变化时有点动效,怎么处理?
老办法: 可使用jQuery来toggle(切换)一个执行动画的类([^译注:CSS的类]),或者直接用jQuery操控要执行动画的元素. state方法: 你能够在props改变时经过componentWillReceiveProps
声明周期函数比较新旧值来响应变化.若是改变了,能够把"animating" state设置为true
.接着执行render
,当"animating"为trur时,添加一个执行动画的CSS类.为false时,不添加类.这里是代码:
componentWillReceiveProps(nextProps) {
if(this.props.counter !== nextProps.counter) {
// Set animating to true right now. When that state change finishes,
// set a timer to set animating false 200ms later.
this.setState({ animating: true }, () => {
setTimeout(() => {
this.setState({ animating: false });
}, 200);
});
}
}
render() {
const animatingClass = this.state.animating ? 'animating' : '';
return (
<div className={`badge ${animatingClass}`}> {this.props.counter} </div>
);
}
复制代码