【全栈React】第6天: 状况

本文转载自:众成翻译
译者: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 组件能够修正它。我们怎样晓得titleHeader 组件的什么 ?我们设置了合作前提,杂沓的数据状况,而且将是一个周全的坏主意,修正由父组件通报给我们的变量并在小孩中修正。

然则,偶然组件须要能够更新自身的状况。比方,active 在秒表上设置标志或更新计时器。

虽然最好props 尽量多地运用,但偶然我们须要对峙组件的状况。为了处置惩罚这个题目,React使我们有才能在组件中具有_状况_。

组件里的state 企图完全是内部的组件,它的孩子(即组件和任何孩子运用它接见)。类似于我们怎样props 在组件中接见,能够经由过程this.state 组件接见状况。不管什么时候状况转变(经由过程 this.setState() ),组件将从新投递。

比方,假定我们有一个简朴的时钟组件来显现当前时候:

纵然这是一个简朴的时钟组件,它确切保存状况,由于它须要晓得当前显现的时候。没有运用state,我们能够设置一个计时器并从新衬着全部React组件,但页面上的其他组件能够不须要从新衬着…这将是一个头痛的题目。

相反,我们能够设置一个计时器来挪用组件内部的rerender并变动此组件的内部状况。

我们来竖立这个组件。起首,我们将建立我们将要挪用的组件Clock。在进入状况之前,我们来构建组件并建立该render() 函数。我们须要斟酌数字,假如数字小于10,在数字前面加上一个零(0),并举行响应的设置 am/pmrender()函数的终究结果能够以下所示:

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.stateClock 组件中有一个定义,我们能够在 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不仅出于机能缘由,最好运用,然则由于有状况的组件更难测试。

本日,我们更新了我们的组件以使其处于状况状况,如今有必要处置惩罚怎样使组件成为状况。来日诰日我们将进入组件的生命周期,什么时候/怎样与页面举行交互。

MenuButton

上面提到的组件在代码库中,只是为菜单按钮供应了一个很好的显现。

const MenuButton = (props) => (
  <div className="menuIcon">
    <div className="dashTop"></div>
    <div className="dashBottom"></div>
    <div className="circle"></div>
  </div>
) 
    原文作者:二月红
    原文地址: https://segmentfault.com/a/1190000010470661
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞