React入門系列 - 3 state與props

3.1 什麼是state

咱們要認識到,React中的組件實際上是一個函數,因此state是函數內部的私有變量,外部其餘組件或者方法都是沒法直接訪問到內部的state。 而state主要被設計用於維持組件內部私有狀態。html

3.1.1 初始化state

初始化state須要在class中constructor進行。react

import React, { PureComponent } from 'react'

export default class index extends PureComponent {
  constructor(props){
    super(props)
    this.state = {name:'demo react',time:new Date()}
  }
  render() {
    return (
      <div> Hello world React!{this.state.name} <p>組件生成時間:{this.state.time}</p> </div>
    )
  }
}

複製代碼

在這個代碼中,咱們初始化了name,time兩個state值。一旦state初始化完成,咱們就能夠在render中進行訪問。webpack

使用npm run dev命令運行,並在瀏覽器中打開查看吧。git

3.1.2 修改state值setState

咱們已經知道了如何初始化組件中的state值,那麼接下來咱們來看看,如何實現修改state的值github

import React, { PureComponent } from 'react'

  export default class index extends PureComponent {
    constructor(props){
      super(props)
      this.state = {name:'demo react',time:+new Date()}
    }
    handleUpdateName () {
      this.state.time = (+new Date())
    }
    render() {
      return (
        <div> Hello world React!{this.state.name} <p>組件生成時間:{this.state.time}</p> <button onClick={this.handleUpdateName.bind(this)}>修改值</button> </div>
      )
    }
  }
複製代碼

有些動做快的同窗,第一個想法就是如此修改組件中的state值,可是值得玩味的是,值的確是修改爲功了,可是,並無實時體如今界面上。這到底是怎麼回事呢?web

這就要來看看,React中的setState方法。算法

React對於setState的定義爲請求React修改某個數據,而React的實現則是將對變量的修改放入一個修改隊列中,在一個循環以後進行批量更新結果(深刻點涉及VDom的更新機制)。因此,這裏會形成一個問題,就是setState數據以後馬上進行讀取,可能你讀取到的數據,並不是是已經被更新過的有效值。npm

setState有三種修改數據的方式,讓咱們來一個一個嘗試。瀏覽器

3.1.2.1 直接賦值
import React, { PureComponent } from 'react'

  export default class index extends PureComponent {
    constructor(props){
      super(props)
      this.state = {name:'demo react',time:+new Date()}
    }
    handleUpdateName () {
      // this.state.time = (+new Date())
      console.log('修改前的值',this.state.time)
      this.setState({time:+new Date()})
      console.log('修改後的值',this.state.time)
      let that = this
      setTimeout(function(){
          console.log('當前state值',that.state.time)
      })
    }
    render() {
      return (
        <div> Hello world React!{this.state.name} <p>組件生成時間:{this.state.time}</p> <button onClick={this.handleUpdateName.bind(this)}>修改值</button> </div>
      )
    }
  }

複製代碼

點擊按鈕,控制檯輸出了不一樣的值,能夠觀察到setState是採用異步隊列模式的。異步

Alt text

3.1.2.2 賦值完成等待同步完成以後執行回調

如今出現了一個問題,若是咱們須要經過等待setState修改完成的值以後,應該如何處理?React爲咱們的setState提供了第二個參數callback

import React, { PureComponent } from 'react'

  export default class index extends PureComponent {
    constructor(props){
      super(props)
      this.state = {name:'demo react',time:+new Date()}
    }
    handleUpdateName () {
      // this.state.time = (+new Date())
      console.log('修改前的值',this.state.time)
      this.setState({time:+new Date()},(function(){
          console.log('當前state值',that.state.time)
      })
      console.log('修改後的值',this.state.time)
    }
    render() {
      return (
        <div> Hello world React!{this.state.name} <p>組件生成時間:{this.state.time}</p> <button onClick={this.handleUpdateName.bind(this)}>修改值</button> </div>
      )
    }
  }

複製代碼

再次運行,而且點擊按鈕。咱們能夠看到控制檯輸出的值是跟第一個方法是一致的。

Alt text

如今咱們來進行一次腦暴,可不能夠直接修改state值呢?由於咱們在最先直接對state修改的時候,React並未關閉這個對象的set方法。那麼咱們能否直接經過修改state來進行渲染呢?React中的一個方法爲咱們解決了這個疑問。

import React, { PureComponent } from 'react'

  export default class index extends PureComponent {
    constructor(props){
      super(props)
      this.state = {name:'demo react',time:+new Date()}
    }
    handleUpdateName () {
        console.log("修改前的值", this.state.time);
        this.state.time = (+new Date())
        console.log("修改後的值", this.state.time);
        console.log("當前state值", this.state.time);
        this.forceUpdate()
    }
    render() {
      return (
        <div> Hello world React!{this.state.name} <p>組件生成時間:{this.state.time}</p> <button onClick={this.handleUpdateName.bind(this)}>修改值</button> </div>
      )
    }
  }
複製代碼

上面這個代碼僅僅用於腦暴,參考,不要在生產環境中使用,由於這個會形成React渲染算法與各類Hook失效,形成全局從新渲染。

3.1.2.3 經過原始數據進行更新

在某些場景下面,咱們多是新的值是基於上一次的值推算而來,因此React提供了setState傳遞進方法來進行推算處理。

import React, { PureComponent } from "react";

export default class index extends PureComponent {
  constructor(props) {
    super(props);
    this.state = { name: "demo react", time: +new Date() };
  }
  handleUpdateName() {
    console.log("修改前的值", this.state.time);
    let that = this;
    this.setState(oldData => {
      return { time: oldData.time + 1000 };
    });
    console.log("修改後的值", this.state.time);
    setTimeout(function() {
      console.log("當前state值", that.state.time);
    });
  }
  render() {
    return (
      <div> Hello world React!{this.state.name} <p>組件生成時間:{this.state.time}</p> <button onClick={this.handleUpdateName.bind(this)}>修改值</button> </div>
    );
  }
}

複製代碼

最後說一點,就是setState是淺拷貝,若是是結構比較深層的對象,不少同窗會採用JSON.string()這種來進行深拷貝,這樣的操做雖說是能夠的,可是很是影響性能。

React推出了immutable與15版本以後推出來的PureComponent就是爲了解決這些問題的。有興趣的同窗能夠搜索一下相關資料進行拓展閱讀。

3.2 什麼是props

咱們知道,在函數中有帶參數的方法,那麼props其實就是傳入方法中的參數。而且在React中props是隻讀屬性。在使用場景上,是由父組件向子組件傳遞值的時候使用的。

3.2.1 接收並渲染props值

咱們首先建立一個能夠接收props值的組件。

import React, { PureComponent } from "react";

export default class index extends PureComponent {
  constructor(props) {
    super(props);
  }
  
  render() {
    return (
      <div style={{'background':'#fefefe'}}> {this.props.value||'暫無數據'} </div>
    );
  }
}
複製代碼

接着,咱們修改Index.js引用這個組件。

import React, { PureComponent } from "react";
import Content from './content.js'
export default class index extends PureComponent {
  constructor(props) {
    super(props);
    this.state = { name: "demo react", time: +new Date() };
  }
  handleUpdateName() {
    this.setState({time:+new Date()})
  }
  render() {
    return (
      <div> Hello world React!{this.state.name} <p>組件生成時間:{this.state.time}</p> <button onClick={this.handleUpdateName.bind(this)}>修改值</button> <Content/> </div>
    );
  }
}

複製代碼

這裏你們有一點要注意,在React中,全部的組件名稱第一個字母都必須大寫,這是爲了與html標籤區分出來。

如何向子組件傳值呢?就像給html標籤增長屬性同樣。

<Content value={'我設置了' + this.state.time}/>
複製代碼

這樣,組件內部能夠經過props讀取到value值了。不過React的組件傳遞中有一個頗有趣的屬性children,這個的用處傳遞組件包含的內容。

繼續修改引入組件的代碼,以下

// index.js
<Content value={'我設置了' + this.state.time} >主體Children</Content>
複製代碼
import React, { PureComponent } from "react";

export default class index extends PureComponent {
  constructor(props) {
    super(props);
  }
  
  render() {
    return (
      <div style={{'background':'#fefefe'}}> {this.props.value||'暫無數據'},children:{this.props.children} </div>
    );
  }
}

複製代碼

最終顯示效果就是這樣的

Alt text

GitHub代碼地址:github.com/yodfz/learn…

原文地址:www.yodfz.com/detail/36/3…

相關文章
相關標籤/搜索