怎样存储 React 组件的数据

主要解说这几个部份:state、store、static、this、module-global data

媒介

跟着 React 和 Redux 的到来,一个配合的题目被问到:

我应当将数据保留在 Redux Store 中呢?照样应当保留成当地 state?

实在这个题目是说的不完整( 或许原文说的太简朴 ),由于你能在组件中存储数据的体式格局另有两种:static 和 this.(实在就是静态数据,照样类的实例数据)

让我们来顺次讨论一下,你应当在什么时刻运用它们。

一、当地 state ( Local state )

ps:下面翻译的时刻将 local state => 直接翻译成 state 吧,关于 state 实在的作用域是与组件挂钩的,直接翻译成当地 state 实际上是不正确的。

当 React 在第一次被引见的时刻,我们就晓得state。我们晓得一个很主要的事变,就是当 state 的值转变的时刻将触发组件的 re-render(从新衬着)。

这个 state 也能通报给子组件,子组件中经由过程 props 来猎取通报的数据,这就许可你能够将你的组件分为:smart data-components(智能数据组件)and dumb presentational-components (填鸭式组件)。

这里有一个运用 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

二、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

三、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 去保留数据。

四、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 来保留数据。

五、其他体式格局…

实际上是有另一个挑选,我没有在标题中申明,由于你不应当如许做:你能够存储在一个全局变量,然后经由过程一个文件举行导出。

这是一个迥殊的场景,然后大多半情况下你不应当如许做。

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

    原文作者:小撸
    原文地址: https://segmentfault.com/a/1190000007186209
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞