top
Loading...
React State(狀態)

React State(狀態)

React 把組件看成是一個狀態機(State Machines)。通過與用戶的交互,實現不同狀態,然後渲染 UI,讓用戶界面和數據保持一致。

React 里,只需更新組件的 state,然後根據新的 state 重新渲染用戶界面(不要操作 DOM)。

以下實例創建一個名稱擴展為 React.Component 的 ES6 類,在 render() 方法中使用 this.state 來修改當前的時間。

添加一個類構造函數來初始化狀態 this.state,類組件應始終使用 props 調用基礎構造函數。

React 實例

class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } render() { return ( <div> <h1>Hello, world!</h1> <h2>現在是 {this.state.date.toLocaleTimeString()}.</h2> </div> ); } } ReactDOM.render( <Clock />, document.getElementById('example') );

嘗試一下 »

接下來,我們將使Clock設置自己的計時器併每秒更新一次。

將生命周期方法添加到類中

在具有許多組件的應用程序中,在銷毀時釋放組件所佔用的資源非常重要。

每當 Clock 組件第一次加載到 DOM 中的時候,我們都想生成定時器,這在 React 中被稱為掛載

同樣,每當 Clock 生成的這個 DOM 被移除的時候,我們也會想要清除定時器,這在 React 中被稱為卸載

我們可以在組件類上聲明特殊的方法,當組件掛載或卸載時,來運行一些代碼:

React 實例

class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div> <h1>Hello, world!</h1> <h2>現在是 {this.state.date.toLocaleTimeString()}.</h2> </div> ); } } ReactDOM.render( <Clock />, document.getElementById('example') );

嘗試一下 »

實例解析:

componentDidMount()componentWillUnmount() 方法被稱作生命周期鉤子。

在組件輸出到 DOM 後會執行 componentDidMount() 鉤子,我們就可以在這個鉤子上設置一個定時器。

this.timerID 為計算器的 ID,我們可以在 componentWillUnmount() 鉤子中卸載計算器。

代碼執行順序:

  1. <Clock /> 被傳遞給 ReactDOM.render() 時,React 調用 Clock 組件的構造函數。 由於 Clock 需要顯示當前時間,所以使用包含當前時間的對象來初始化 this.state 。 我們稍後會更新此狀態。

  2. React 然後調用 Clock 組件的 render() 方法。這是 React 了解屏幕上應該顯示什么內容,然後 React 更新 DOM 以匹配 Clock 的渲染輸出。

  3. Clock 的輸出插入到 DOM 中時,React 調用 componentDidMount() 生命周期鉤子。 在其中,Clock 組件要求瀏覽器設置一個定時器,每秒鐘調用一次 tick()

  4. 瀏覽器每秒鐘調用 tick() 方法。 在其中,Clock 組件通過使用包含當前時間的對象調用 setState() 來調度UI更新。 通過調用 setState() ,React 知道狀態已經改變,併再次調用 render() 方法來確定屏幕上應當顯示什么。 這一次,render() 方法中的 this.state.date 將不同,所以渲染輸出將包含更新的時間,併相應地更新 DOM。

  5. 一旦 Clock 組件被從 DOM 中移除,React 會調用 componentWillUnmount() 這個鉤子函數,定時器也就會被清除。

數據自頂向下流動

父組件或子組件都不能知道某個組件是有狀態還是無狀態,併且它們不應該關心某組件是被定義為一個函數還是一個類。

這就是為什么狀態通常被稱為局部或封裝。 除了擁有併設置它的組件外,其它組件不可訪問。

以下實例中 FormattedDate 組件將在其屬性中接收到 date 值,併且不知道它是來自 Clock 狀態、還是來自 Clock 的屬性、亦或手工輸入:

React 實例

function FormattedDate(props) { return <h2>現在是 {props.date.toLocaleTimeString()}.</h2>; } class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div> <h1>Hello, world!</h1> <FormattedDate date={this.state.date} /> </div> ); } } ReactDOM.render( <Clock />, document.getElementById('example') );

嘗試一下 »

這通常被稱為自頂向下或單向數據流。 任何狀態始終由某些特定組件所有,併且從該狀態導出的任何數據或 UI 只能影響樹中下方的組件。

如果你想象一個組件樹作為屬性的瀑布,每個組件的狀態就像一個額外的水源,它連接在一個任意點,但也流下來。

為了表明所有組件都是真正隔離的,我們可以創建一個 App 組件,它渲染三個Clock:

React 實例

function FormattedDate(props) { return <h2>現在是 {props.date.toLocaleTimeString()}.</h2>; } class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div> <h1>Hello, world!</h1> <FormattedDate date={this.state.date} /> </div> ); } } function App() { return ( <div> <Clock /> <Clock /> <Clock /> </div> ); } ReactDOM.render(<App />, document.getElementById('example'));

嘗試一下 »

以上實例中每個 Clock 組件都建立了自己的定時器併且獨立更新。

在 React 應用程序中,組件是有狀態還是無狀態被認為是可能隨時間而變化的組件的實現細節。

我們可以在有狀態組件中使用無狀態組件,也可以在無狀態組件中使用有狀態組件。

北斗有巢氏 有巢氏北斗