如何存儲 React 組件的數據

主要講解這幾個部分:state、store、static、this、module-global datajavascript

前言

隨着 React 和 Redux 的到來,一個共同的問題被問到:html

我應該將數據保存在 Redux Store 中呢?仍是應該保存成本地 state?java

其實這個問題是說的不完整( 或者原文說的太簡單 ),由於你能在組件中存儲數據的方式還有兩種:static 和 this.(其實就是靜態數據,仍是類的實例數據)react

讓咱們來依次討論一下,你應該在何時使用它們。git

1、本地 state ( Local state )

ps:下面翻譯的時候將 local state => 直接翻譯成 state 吧,對於 state 其實的做用域是與組件掛鉤的,直接翻譯成本地 state 實際上是不許確的。github

當 React 在第一次被介紹的時候,咱們就知道state。咱們知道一個很重要的事情,就是當 state 的值改變的時候將觸發組件的 re-render(從新渲染)。redux

這個 state 也能傳遞給子組件,子組件中經過 props 來獲取傳遞的數據,這就容許你可以將你的組件分爲:smart data-components(智能數據組件)and dumb presentational-components (填鴨式組件)。api

這裏有一個使用 state 來編寫的 counter app(計數 APP):數組

import React from 'react'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      counter: 0
    }
    this.addOne = this.addOne.bind(this)
  }
  
  addOne() {
    this.setState({
      counter: this.state.counter + 1
    })
  }
  
  render() {
    return (
      <div>
        <button
          onClick={ this.addOne }>
          Increment
        </button>
        { this.state.counter }
      </div>
    )
  }
}

export default App

你的數據( counter 的值 )是存儲在 App 組件中,也能向下傳遞給子組件。安全

& 應用場景

假如 counter 數據在你的 app 中是很重要的,以及這個數據會存儲下來用於其餘組件,那麼你將不但願使用 state 來保存這個值。

這最好的實踐是處理用戶接口 (UI, User Interface) 的狀態數據。好比:使用一個 交互組件 去填寫表單,這時候使用 state 是不錯的選擇。

另外的例子,就是在 UI 交互相關的數據中使用,好比你將在一個列表中記錄當前選中的 tab (選項卡)的狀態,你就能存儲一個 state

在你選擇 state 的使用時機,也可以這樣考慮:你存儲的數據是否會在其餘組件中使用。若是一個值是隻有一個組件(或者也許只有一個子組件),這時使用 state 來保持這個值(或者說狀態)都是安全的。

總結:保持 UI 狀態和暫時的數據(好比:表單的輸入),可以使用 state

2、Redux store

隨着發展,每一個人開始選擇單向數據流, 咱們選擇 Redux。

對於 Redux,咱們將得到一個全局的 store。這個 store 將綁定在一個最高等級的組件中,而後將 App 的數據流入全部的子組件(其實整個 App 就已是這個最高等級組件的子組件了)。你能 connect 全局 store,使用:connect wrap 和 mapStateToProps 方法.

首先,人們就將任何事情都交給了 Redux store。好比:Users, modals, forms, sockets...,主要你知道的。

下面是一個和以前相同的計數 App,而後使用了 Redux。主要須要注意的是 counter 數據,使用 mapStateToProps 映射了數據,而且使用 connect 方法包裹組件,this.state.counter 如今就變成了 this.props.counter,而後這個值就是經過全局 store 獲取的,這個全局 store 將值傳遞給當前組件的 props。(若是想知道具體,我在 React.js 模式的文章中有介紹原理)。

import React from 'react'
import { connect } from 'react-redux'
import Actions from './Actions.js'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.addOne = this.addOne.bind(this)
  }
  
  addOne() {
    this.props.dispatch(Actions.addOne())
  }
  
  render() {
    return (
      <div>
        <button
          onClick={ this.addOne }>
          Increment
        </button>
        { this.props.counter }
      </div>
    )
  }
}

const mapStateToProps = store => {
  return {
    counter: store.counter
  }
}

export default connect(mapStateToProps)(App)

如今當你點擊按鈕的時候,經過一個 action => dispatched 使全局 store 更新。而後這個數據經過外層組件傳遞到當前組件。

值得注意的是:當 props 被更新的時候,這也將觸發組件的 re-render(從新渲染)=> 這與你更新 state 的時候同樣。

& 應用場景

對於 Redux store 是很好的保持了除 UI 狀態數據外的應用狀態。有一個不錯的例子,好比用戶的登陸狀態。對於在在登陸狀態改變的同時,多數組件須要訪問這個數據信息作出響應。這些組件(至少有一個被渲染)將須要從新渲染與更新的信息。

Redux 觸發事件在你須要跨組件或者跨路由的狀況下是頗有用的。好比有一個登陸彈框,當你的 App 中有多個按鈕點擊都將觸發彈出它的時候。而不是在你須要渲染這個彈框的多個地方作判斷,你能經過一個頂層的 App 組件去使用 Redux action 去觸發它而且修改 store 的值。

總結:你想將跨組件的保持數據的時候可以使用 store

3、this.<something>

在 React 的開發中,使用 this 來保存數據的場景不多。人們常常忘記了 React 使用的是 JavaScript 的 ES2015 的語法。任何你可以用 JavaScript 作的事情,你都能在 React 作(這也是我很是喜歡 React 的緣由呢 ^0^ freedom)。

下面的例子依然是一個計數應用,與以前的例子有點相似。

import React from 'react'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.counter = 0
    this.addOne = this.addOne.bind(this)
  }
  
  addOne() {
    this.counter += 1
    this.forceUpdate()
  }
  
  render() {
    return (
      <div>
        <button
          onClick={ this.addOne }>
          Increment
        </button>
        { this.counter }
      </div>
    )
  }
}

export default App

咱們是在組件中使用 this 存儲 counter 變量的值,而且使用 forceUpdate() 方法來觸發組件的從新渲染。這是由於沒有任何的 state 和 props 修改,所以沒有自動觸發從新渲染機制。

這個例子實際上不該該使用 this。若是你發現你必須使用 forceUpdate() 才能知足需求,你可能代碼哪裏出了問題。若是想值修改的時候自動觸發從新渲染,你應該使用 state 或者 props/Redux store(其實嚴格一點來講,做者這裏的表述是不清的,其實從新渲染與 Redux 並沒有關係,本質上就是 props 的更新流入組件)。

& 應用場景

使用 this 來保存數據的時候,可以在改變的時候不須要去觸發從新渲染的場景。好比:sockets 是很好的一個使用 this 保存數據的場景。

import React from 'react'
import { Socket } from 'phoenix'

class App extends React.Component {
  componentDidMount() {
    this.socket = new Socket('http://localhost:4000/socket')
    this.socket.connect()
    this.configureChannel("lobby")
  }
  
  componentWillUnmount() {
    this.socket.leave()
  }
  
  configureChannel(room) {
    this.channel = this.socket.channel(`rooms:${room}`)
    this.channel.join()
      .receive("ok", () => {
        console.log(`Succesfully joined the ${room} chat room.`)
      })
      .receive("error", () => {
        console.log(`Unable to join the ${room} chat room.`)
      })
  }
  
  render() {
    return (
      <div>
        My App
      </div>
    )
  }
}

export default App

大多數人們沒有他們以前一直在使用 this 定義方法。放你定義 render(),你其實是:this.prototype.render = function () { },可是這在 ES2015 的 class 語法機制下是隱式的。

總結:在不須要數據改變的時候去觸發從新渲染機制的時候,可以使用 this 去保存數據。

4、Static(靜態的方式)

靜態方法和屬性也許是最少使用的(靜下來,我知道他們不是真正在 class 下的一個機制),大多數是由於他們沒有被頻繁使用。可是他們不是很複雜。若是你用過 PropTypes,你就定義了一個 static 屬性。

下面有兩份代碼塊其實是長得同樣的。人們常用的方式是第一種,第二種是你能使用 static 關鍵字來定義。

class App extends React.Component {
  render() {
    return (<div>{ this.props.title }</div>)
  }
}

App.propTypes = {
  title: React.PropTypes.string.isRequired
}
class App extends React.Component {
  static propTypes {
    title: React.PropTypes.string.isRequired
  }
  
  render() {
    return (<div>{ this.props.title }</div>)
  }
}

正如你看到的,static 並不複雜。他們是一種另外的方式去聲明一個類的值。這主要的不一樣是 static 不要像 this 那樣去實例化一個類再去訪問值。

class App extends React.Component {
  constructor() {
    super()
    this.prototypeProperty = {
      baz: "qux"
    }
  }
  static staticProperty = {
    foo: "bar"
  };
  
  render() {
    return (<div>My App</div>)
  }
}

const proto = new App();
const proto2 = proto.prototypeProperty // => { baz: "qux" }

const stat = App.staticProperty // => { foo: "bar" }

在這個例子中,你能看獲取 staticProperty 的值,咱們只組要直接經過類名去訪問,而不是實例後。可是訪問 proto.prototypeProperty 就必需要 new App().

& 應用場景

靜態方法和屬性是不多被使用,主要被用來定義工具方法或者特定類型的全部組件。

propTypes 是一個工具例子,好比一個 Button 組件,每個按鈕的渲染都須要類似的值。

另外個案例就是若是你關注獲取的數據。若是你是使用 GraphQL 或者 Falcor,你能具體描述須要服務端返回什麼數據。這種方法你能不用接受大量組件不須要的數據。

class App extends React.Component {
  static requiredData = [
    "username",
    "email",
    "thumbnail_url"
  ]
  
  render() {
    return(<div></div>)
  }
}

所以在例子中,在特殊組件請求數據以前,你能使用 App.requiredData 快速獲取必要的 query 的值。

總結:你也許幾乎不會使用 static 來保存數據。

5、其餘方式...

實際上是有另外一個選擇,我沒有在標題中說明,由於你不該該這樣作:你能夠存儲在一個全局變量,而後經過一個文件進行導出。

這是一個特別的場景,而後大多數狀況下你不該該這樣作。

import React from 'react'

let counter = 0

class App extends React.Component {
  constructor(props) {
    super(props)
    this.addOne = this.addOne.bind(this)
  }
  
  addOne() {
    counter += 1
    this.forceUpdate()
  }
  
  render() {
    return (
      <div>
        <button
          onClick={ this.addOne }>
          Increment
        </button>
        { counter }
      </div>
    )
  }
}

export default App

你可以看到和使用 this 是相似的,除了使用的是一個全局的變量。

若是你須要跨組件的共享數據以及保存一個全局變量,大多數更好的是使用 Redux store

總結:不要使用全局變量。

原文出自:https://medium.freecodecamp.com/where-do-i-belong-a-guide-to-saving-react-component-data-in-state-store-static-and-this-c49b335e2a00#.yvhqqxdkh

相關文章
相關標籤/搜索