本文转载自:众成翻译
译者:iOSDevLog
连接:http://www.zcfy.cc/article/3824
原文:https://www.fullstackreact.com/30-days-of-react/day-6/react
今天咱们开始了解React中有状态组件的工做原理,而且看看咱们什么时候以及为何要使用状态。函数
咱们几乎完成了在React开始运行的第一周。咱们经过JSX工做,构建咱们的第一个组件,设置父子关系,并使用React驱动组件属性。咱们还有一个重要的想法,咱们尚未讨论React _状态_相关的知识。性能
状态
的事React并无让咱们修改this.props
咱们有充分的理由的组件。想象一下,若是咱们将 title
属性支持传递给Header
组件,而且Header
组件可以修改它。咱们如何知道title
是Header
组件的什么 ?咱们设置了竞争条件,混乱的数据状态,而且将是一个全面的坏主意,修改由父组件传递给咱们的变量并在小孩中修改。测试
然而,有时组件须要可以更新本身的状态。例如,active
在秒表上设置标志或更新计时器。this
虽然最好props
尽量多地使用,但有时咱们须要坚持组件的状态。为了处理这个问题,React使咱们有能力在组件中拥有_状态_。spa
组件里的state
意图彻底是内部的组件,它的孩子(即组件和任何孩子使用它访问)。相似于咱们如何props
在组件中访问,能够经过this.state
组件访问状态。不管什么时候状态改变(经过 this.setState()
),组件将从新投递。翻译
例如,假设咱们有一个简单的时钟组件来显示当前时间:code
即便这是一个简单的时钟组件,它确实保留状态,由于它须要知道当前显示的时间。没有使用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(); }
构造函数的第一行应该_始终_调用
super(props)
。若是您忘记了这一点,组件将不会很是喜欢(即会有错误)。
如今咱们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>
组件。
尝试一下!点击下面的搜索图标:(想要有效果仍是去原文体验吧?)
知道咱们如今知道的是,如今 this.state
咱们能够更新视图来添加条件呈现<input>
class Header extends React.Component { constructor(props) { super(props); this.state = { searchVisible: false } } // toggle visibility when run on the state showSearch() { this.setState({ searchVisible: !this.state.searchVisible }) } render() { // Classes to add to the <input /> element let searchInputClasses = ["searchInput"]; // Update the class array if the state is visible if (this.state.searchVisible) { searchInputClasses.push("active"); } return ( <div className="header"> <MenuButton /> <span className="title"> {this.props.title} </span> <input type="text" className={searchInputClasses.join(' ')} placeholder="Search ..." /> {/* Adding an onClick handler to call the showSearch button */} <div onClick={this.showSearch.bind(this)} className="fa fa-search searchIcon"></div> </div> ) } }
this.setState()
一个对象参数时,它将执行一个数据的_浅合并_到可用的对象中this.setState()
,而后从新渲染组件。render()
函数中使用的值。从上面咱们的时钟的例子,请注意,咱们的存储hours
,minutes
,以及seconds
在咱们的状态。在咱们不打算在render功能中使用的状态下存储对象或计算一般是一个坏主意,由于它可能致使没必要要的渲染和浪费的CPU周期。正如咱们在本节顶部指出的那样,props不只出于性能缘由,最好使用,可是由于有状态的组件更难测试。
今天,咱们更新了咱们的组件以使其处于状态状态,如今有必要处理如何使组件成为状态。明天咱们将进入组件的生命周期,什么时候/如何与页面进行交互。
上面提到的组件在代码库中,只是为菜单按钮提供了一个很好的显示。
const MenuButton = (props) => ( <div className="menuIcon"> <div className="dashTop"></div> <div className="dashBottom"></div> <div className="circle"></div> </div> )