本文转载自:众成翻译
译者:iOSDevLog
链接:http://www.zcfy.cc/article/3824
原文:https://www.fullstackreact.com/30-days-of-react/day-6/
今天我们开始了解React中有状态组件的工作原理,并且看看我们何时以及为什么要使用状态。
我们几乎完成了在React开始运行的第一周。我们通过JSX工作,构建我们的第一个组件,设置父子关系,并使用React驱动组件属性。我们还有一个重要的想法,我们还没有讨论React _状态_相关的知识。
有关状态
的事
React并没有让我们修改this.props
我们有充分的理由的组件。想象一下,如果我们将 title
属性支持传递给Header
组件,并且Header
组件能够修改它。我们如何知道title
是Header
组件的什么 ?我们设置了竞争条件,混乱的数据状态,并且将是一个全面的坏主意,修改由父组件传递给我们的变量并在小孩中修改。
然而,有时组件需要能够更新自己的状态。例如,active
在秒表上设置标志或更新计时器。
虽然最好props
尽可能多地使用,但有时我们需要坚持组件的状态。为了处理这个问题,React使我们有能力在组件中拥有_状态_。
组件里的state
意图完全是内部的组件,它的孩子(即组件和任何孩子使用它访问)。类似于我们如何props
在组件中访问,可以通过this.state
组件访问状态。无论何时状态改变(通过 this.setState()
),组件将重新投递。
例如,假设我们有一个简单的时钟组件来显示当前时间:
即使这是一个简单的时钟组件,它确实保留状态,因为它需要知道当前显示的时间。没有使用state,我们可以设置一个计时器并重新渲染整个React组件,但页面上的其他组件可能不需要重新渲染…这将是一个头痛的问题。
相反,我们可以设置一个计时器来调用组件内部的rerender并更改此组件的内部状态。
我们来建立这个组件。首先,我们将创建我们将要调用的组件Clock
。在进入状态之前,我们来构建组件并创建该render()
函数。我们需要考虑数字,如果数字小于10,在数字前面加上一个零(0
),并进行相应的设置 am/pm
。 render()
函数的最终结果可能如下所示:
class Clock extends React.Component { render() { const currentTime = new Date(),hours = currentTime.getHours(),minutes = currentTime.getMinutes(),seconds = currentTime.getSeconds(),ampm = hours >= 12 ? 'pm' : 'am'; return ( <div className="clock"> { hours == 0 ? 12 : (hours > 12) ? hours - 12 : hours }:{ minutes > 9 ? minutes : `0${minutes}` }:{ seconds > 9 ? seconds : `0${seconds}` } {ampm} </div> ) } } // ... export default Clock
如果我们渲染我们的新Clock
组件,我们只会在组件本身重新运行时获得时间。这不是一个非常有用的时钟(还)。为了将静态时间显示Clock
组件转换为显示时间的时钟,我们需要每秒更新一次。
为了做到这一点,我们需要跟踪组件状态下的_current_ 时间。 为此,我们需要设置初始状态值。 在ES6类样式中,我们可以通过将this.state
设置为一个值来设置constructor()
中组件的初始状态。
constructor(props) { super(props); this.state = this.getTime(); }
现在我们this.state
在Clock
组件中有一个定义,我们可以在 render()
函数中引用它this.state
。让我们更新我们的 render()
函数this.state
来获取以下值:
class Clock extends React.Component { // ... render() { const {hours,minutes,seconds,ampm} = this.state; return ( <div className="clock"> { hours === 0 ? 12 : (hours > 12) ? hours - 12 : hours }:{ minutes > 9 ? minutes : `0${minutes}` }:{ seconds > 9 ? seconds : `0${seconds}` } {ampm} </div> ) } }
我们现在可以更新 state
组件而不是直接使用数据值。为了更新状态,我们将使用该函数 this.setState()
,这将触发组件重新渲染。
在我们的Clock
组件中,我们使用本机setTimeout()
JavaScript函数创建一个定时器,以this.state
在1000毫秒内更新对象。我们将把这个功能放在一个函数中,我们再次调用它。
class Clock extends React.Component { // ... constructor(props) { super(props); this.state = this.getTime(); } // ... setTimer() { clearTimeout(this.timeout); this.timeout = setTimeout(this.updateClock.bind(this),1000); } // ... updateClock() { this.setState(this.getTime,this.setTimer); } // ... }
我们将在下一节中介绍生命周期中的钩子,但是为了简单起见,我们暂时将其简称为
constructor()
。
在该 updateClock()
函数中,我们将要在新时间内更新状态。我们现在可以在 updateClock()
函数中更新状态:
class Clock extends React.Component { // ... updateClock() { this.setState(this.getTime,this.setTimer); } // ... }
该组件将安装在页面上,并在(大约)一秒钟(1000毫秒)内更新当前时间。但是,它不会再重新设置。我们可以在setTimer()
函数结束时再次调用该函数:
class Clock extends React.Component { // ... updateClock() { const currentTime = new Date(); this.setState({ currentTime: currentTime }) this.setTimer(); } // ... }
现在,组件本身可能会比超时功能再次调用慢,这将导致重新出现的瓶颈,并且不必要地在移动设备上使用宝贵的电池。在调用setTimer()
函数之后this.setState()
,我们可以将第二个参数传递给this.setState()
函数,该函数将在状态更新_后_保证被调用。
class Clock extends React.Component { // ... updateClock() { const currentTime = new Date(); this.setState({ currentTime: currentTime },this.setTimer); } // ... }
更新我们的活动列表
我们可以Header
在上一节中我们一直在研究的活动列表中更新我们的组件。当用户点击search
图标,我们将要显示<input>
组件。