React 能夠直接下載使用,下載包中也提供了不少學習的實例。css
本教程使用了 React 的版本爲 16.4.0,你能夠在官網 https://reactjs.org/ 下載最新版。html
你也能夠直接使用 Staticfile CDN 的 React CDN 庫,地址以下:react
<!-- 生產環境中不建議使用 -->webpack
官方提供的 CDN 地址:git
<!-- 生產環境中不建議使用 -->github
NPM管理web
npm install --save react react-dom babelify babel-preset-react
npm install --save babel-preset-es2015
使用webpack打包配置
全局安裝webpack
npm install -g webpack
全局安裝完webpack還須要項目下安裝npm install webpack --save
全局安裝webpack開發服務器
npm install -g webpack-dev-server
全局安裝完webpack-dev-server 後還須要在當前目錄下安裝npm install webpack-dev-server --save
如下實例輸出了 Hello, world!npm
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello React!</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
</script>
</body>
</html>
實例解析:json
實例中咱們引入了三個庫: react.min.js 、react-dom.min.js 和 babel.min.js:api
react.min.js - React 的核心庫
react-dom.min.js - 提供與 DOM 相關的功能
babel.min.js - Babel 能夠將 ES6 代碼轉爲 ES5 代碼,這樣咱們就能在目前不支持 ES6 瀏覽器上執行 React 代碼。Babel 內嵌了對 JSX 的支持。經過將 Babel 和 babel-sublime 包(package)一同使用可讓源碼的語法渲染上升到一個全新的水平。
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
以上代碼將一個 h1 標題,插入 id="example" 節點中。
注意:
若是咱們須要使用 JSX,則 <script> 標籤的 type 屬性須要設置爲 text/babel。
國內使用 npm 速度很慢,你可使用淘寶定製的 cnpm (gzip 壓縮支持) 命令行工具代替默認的 npm:
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
$ npm config set registry https://registry.npm.taobao.org
這樣就可使用 cnpm 命令來安裝模塊了:
$ cnpm install [name]
create-react-app 是來自於 Facebook,經過該命令咱們無需配置就能快速構建 React 開發環境。
create-react-app 自動建立的項目是基於 Webpack + ES6 。
執行如下命令建立項目:
$ cnpm install -g create-react-app
$ create-react-app my-app
$ cd my-app/
$ npm start
manifest.json 指定了開始頁面 index.html,一切的開始都從這裏開始,因此這個是代碼執行的源頭。
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>歡迎來到hello world</h2>
</div>
<p className="App-intro">
你能夠在 <code>src/App.js</code> 文件中修改。
</p>
</div>
);
}
}
export default App;
元素是構成 React 應用的最小單位,它用於描述屏幕上輸出的內容。
const element = <h1>Hello, world!</h1>;
首先咱們在一個 HTML 頁面中添加一個 id="example" 的 <div>:
<div id="example"></div>
在此 div 中的全部內容都將由 React DOM 來管理,因此咱們將其稱之爲 "根" DOM 節點。
咱們用 React 開發應用時通常只會定義一個根節點。但若是你是在一個已有的項目當中引入 React 的話,你可能會須要在不一樣的部分單獨定義 React 根節點。
要將React元素渲染到根DOM節點中,咱們經過把它們都傳遞給 ReactDOM.render() 的方法來將其渲染到頁面上:
實例:
const element = <h1>Hello, world!</h1>;
ReactDOM.render(
element,
document.getElementById('example')
);
React 元素都是不可變的。當元素被建立以後,你是沒法改變其內容或屬性的。
目前更新界面的惟一辦法是建立一個新的元素,而後將它傳入 ReactDOM.render() 方法:
來看一下這個計時器的例子:
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>如今是 {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('example')
);
}
setInterval(tick, 1000);
以上實例經過 setInterval() 方法,每秒鐘調用一次 ReactDOM.render()。
咱們能夠將要展現的部分封裝起來,如下實例用一個函數來表示:
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>如今是 {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('example')
);
}
setInterval(tick, 1000);
除了函數外咱們還能夠建立一個 React.Component 的 ES6 類,該類封裝了要展現的元素,須要注意的是在 render() 方法中,須要使用 this.props 替換 props:
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>如今是 {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('example')
);
}
setInterval(tick, 1000);
React 只會更新必要的部分
值得注意的是 React DOM 首先會比較元素內容前後的不一樣,而在渲染過程當中只會更新改變了的部分。
React 使用 JSX 來替代常規的 JavaScript。
JSX 是一個看起來很像 XML 的 JavaScript 語法擴展。
咱們不須要必定使用 JSX,但它有如下優勢:
JSX 執行更快,由於它在編譯爲 JavaScript 代碼後進行了優化。
它是類型安全的,在編譯過程當中就能發現錯誤。
使用 JSX 編寫模板更加簡單快速。
JSX 看起來相似 HTML ,咱們能夠看下實例:
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
咱們能夠在以上代碼中嵌套多個 HTML 標籤,須要使用一個 div 元素包裹它,實例中的 p 元素添加了自定義屬性 data-myattribute,添加自定義屬性須要使用 data- 前綴。
ReactDOM.render(
<div>
<h1>hello world</h1>
<h2>歡迎學習 React</h2>
<p data-myattribute = "somevalue">這是一個很不錯的 JavaScript 庫!</p>
</div>
,
document.getElementById('example')
);
你的 React JSX 代碼能夠放在一個獨立文件上,例如咱們建立一個 helloworld_react.js
文件,代碼以下:
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
而後在 HTML 文件中引入該 JS 文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Hello React!</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel" src="./hellow_react.js"></script>
</body>
</html>
咱們能夠在 JSX 中使用 JavaScript 表達式。表達式寫在花括號 {} 中。實例以下:
ReactDOM.render(
<div>
<h1>{1+1}</h1>
</div>
,
document.getElementById('example')
);
在 JSX 中不能使用 if else 語句,但可使用 conditional (三元運算) 表達式來替代。如下實例中若是變量 i 等於 1 瀏覽器將輸出 true, 若是修改 i 的值,則會輸出 false.
ReactDOM.render(
<div>
<h1>{i == 1 ? 'True!' : 'False'}</h1>
</div>
,
document.getElementById('example')
);
React 推薦使用內聯樣式。咱們可使用 camelCase 語法來設置內聯樣式. React 會在指定元素數字後自動添加 px 。如下實例演示了爲 h1 元素添加 myStyle 內聯樣式:
var myStyle = {
fontSize: 100,
color: '#FF0000'
};
ReactDOM.render(
<h1 style = {myStyle}>hello world</h1>,
document.getElementById('example')
);
註釋須要寫在花括號中,實例以下:
ReactDOM.render(
<div>
<h1>hello world</h1>
{/*註釋...*/}
</div>,
document.getElementById('example')
);
JSX 容許在模板中插入數組,數組會自動展開全部成員:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Hello React!</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
var arr = [
<h1>cainiaojiaocheng</h1>,
<h2>是時候展現真正的技術了</h2>,
];
ReactDOM.render(
<div>{arr}</div>,
document.getElementById("example")
)
</script>
</body>
</html>
React 能夠渲染 HTML 標籤 (strings) 或 React 組件 (classes)。
要渲染 HTML 標籤,只需在 JSX 裏使用小寫字母的標籤名。
var myDivElement = <div className="foo" />;
ReactDOM.render(myDivElement, document.getElementById('example'));
要渲染 React 組件,只需建立一個大寫字母開頭的本地變量
var MyComponent = React.createClass({/*...*/});
var myElement = <MyComponent someProperty={true} />;
ReactDOM.render(myElement, document.getElementById('example'));
React 的 JSX 使用大、小寫的約定來區分本地組件的類和 HTML 標籤。
注意:
因爲 JSX 就是 JavaScript,一些標識符像 class
和 for
不建議做爲 XML 屬性名。做爲替代,React DOM 使用 className
和 htmlFor
來作對應的屬性。
接下來咱們封裝一個輸出 "Hello World!" 的組件,組件名爲 HelloMessage:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Hello React!</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
function HelloCompent(params) {
return <h1>hellow amisu</h1>;
}
const element = <HelloCompent/>
ReactDOM.render(
element,
document.getElementById("example")
)
</script>
</body>
</html>
一、咱們可使用函數定義了一個組件:
function HelloMessage(props) {
return <h1>Hello World!</h1>;
}
你也可使用 ES6 class 來定義一個組件:
class Welcome extends React.Component {
render() {
return <h1>Hello World!</h1>;
}
}
二、const element = <HelloMessage /> 爲用戶自定義的組件。
注意,原生 HTML 元素名以小寫字母開頭,而自定義的 React 類名以大寫字母開頭,好比 HelloMessage 不能寫成 helloMessage。除此以外還須要注意組件類只能包含一個頂層標籤,不然也會報錯。
若是咱們須要向組件傳遞參數,可使用 this.props 對象,實例以下:
function HelloMessage(props) {
return <h1>Hello {props.name}!</h1>;
}
const element = <HelloMessage name="Runoob"/>;
ReactDOM.render(
element,
document.getElementById('example')
);
以上實例中 name 屬性經過 props.name 來獲取。
注意,在添加屬性時, class 屬性須要寫成 className ,for 屬性須要寫成 htmlFor ,這是由於 class 和 for 是 JavaScript 的保留字。
咱們能夠經過建立多個組件來合成一個組件,即把組件的不一樣功能點進行分離。
如下實例咱們實現了輸出網站名字和網址的組件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Hello React!</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
function Name(props) {
return <h1>網站名稱:{props.name}</h1>;
}
function Url(props) {
return <h1>網站地址:{props.url}</h1>;
}
function App() {
return (
<div>
<Name name="hello world" />
<Url url="http://www.runoob.com" />
</div>
);
}
ReactDOM.render(
<App/>,
document.getElementById("example")
)
</script>
</body>
</html>
實例中 App 組件使用了 Name、Url 組件來輸出對應的信息。
React 把組件當作是一個狀態機(State Machines)。經過與用戶的交互,實現不一樣狀態,而後渲染 UI,讓用戶界面和數據保持一致。
React 裏,只需更新組件的 state,而後根據新的 state 從新渲染用戶界面(不要操做 DOM)。
如下實例建立一個名稱擴展爲 React.Component 的 ES6 類,在 render() 方法中使用 this.state 來修改當前的時間。
添加一個類構造函數來初始化狀態 this.state,類組件應始終使用 props 調用基礎構造函數。
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 中被稱爲卸載。
咱們能夠在組件類上聲明特殊的方法,當組件掛載或卸載時,來運行一些代碼:
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() 鉤子中卸載計算器。
代碼執行順序:
當 <Clock />
被傳遞給 ReactDOM.render()
時,React 調用 Clock
組件的構造函數。 因爲 Clock
須要顯示當前時間,因此使用包含當前時間的對象來初始化 this.state
。 咱們稍後會更新此狀態。
React 而後調用 Clock
組件的 render()
方法。這是 React 瞭解屏幕上應該顯示什麼內容,而後 React 更新 DOM 以匹配 Clock
的渲染輸出。
當 Clock
的輸出插入到 DOM 中時,React 調用 componentDidMount()
生命週期鉤子。 在其中,Clock
組件要求瀏覽器設置一個定時器,每秒鐘調用一次 tick()
。
瀏覽器每秒鐘調用 tick()
方法。 在其中,Clock
組件經過使用包含當前時間的對象調用 setState()
來調度UI更新。 經過調用 setState()
,React 知道狀態已經改變,並再次調用 render()
方法來肯定屏幕上應當顯示什麼。 這一次,render()
方法中的 this.state.date
將不一樣,因此渲染輸出將包含更新的時間,並相應地更新 DOM。
一旦 Clock
組件被從 DOM 中移除,React 會調用 componentWillUnmount()
這個鉤子函數,定時器也就會被清除。
父組件或子組件都不能知道某個組件是有狀態仍是無狀態,而且它們不該該關心某組件是被定義爲一個函數仍是一個類。
這就是爲何狀態一般被稱爲局部或封裝。 除了擁有並設置它的組件外,其它組件不可訪問。
如下實例中 FormattedDate 組件將在其屬性中接收到 date 值,而且不知道它是來自 Clock 狀態、仍是來自 Clock 的屬性、亦或手工輸入:
爲了代表全部組件都是真正隔離的,咱們能夠建立一個 App 組件,它渲染三個Clock:
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 應用程序中,組件是有狀態仍是無狀態被認爲是可能隨時間而變化的組件的實現細節。
咱們能夠在有狀態組件中使用無狀態組件,也能夠在無狀態組件中使用有狀態組件。
state 和 props 主要的區別在於 props 是不可變的,而 state 能夠根據與用戶交互來改變。這就是爲何有些容器組件須要定義 state 來更新和修改數據。 而子組件只能經過 props 來傳遞數據。
function HelloMessage(props) { return <h1>Hello {props.name}!</h1>; } const element = <HelloMessage name="Runoob"/>; ReactDOM.render( element, document.getElementById('example') );
你能夠經過組件類的 defaultProps 屬性爲 props 設置默認值,實例以下:
class HelloMessage extends React.Component { render() { return ( <h1>Hello, {this.props.name}</h1> ); } } HelloMessage.defaultProps = { name: 'Runoob' }; const element = <HelloMessage/>; ReactDOM.render( element, document.getElementById('example') );
如下實例演示瞭如何在應用中組合使用 state 和 props 。咱們能夠在父組件中設置 state, 並經過在子組件上使用 props 將其傳遞到子組件上。在 render 函數中, 咱們設置 name 和 site 來獲取父組件傳遞過來的數據。
class WebSite extends React.Component { constructor() { super(); this.state = { name: "hello world", site: "https://www.runoob.com" } } render() { return ( <div> <Name name={this.state.name} /> <Link site={this.state.site} /> </div> ); } } class Name extends React.Component { render() { return ( //ES6方法接收參數用的是this.props.xxx,函數式直接props.xx <h1>{this.props.name}</h1> ); } } class Link extends React.Component { render() { return ( <a href={this.props.site}> {this.props.site} </a> ); } } ReactDOM.render( <WebSite />, document.getElementById('example') );
React 元素的事件處理和 DOM 元素相似。可是有一點語法上的不一樣:
React 事件綁定屬性的命名採用駝峯式寫法,而不是小寫。
若是採用 JSX 的語法你須要傳入一個函數做爲事件處理函數,而不是一個字符串(DOM 元素的寫法)
HTML 一般寫法是:
<button onclick="activateLasers()"> 激活按鈕 </button>
React 中寫法爲:
<button onClick={activateLasers}> 激活按鈕 </button>
在 React 中另外一個不一樣是你不能使用返回 false 的方式阻止默認行爲, 你必須明確的使用 preventDefault。
<a href="#" onclick="console.log('點擊連接'); return false"> 點我 </a>
在 React 的寫法爲:
function ActionLink() { function handleClick(e) { e.preventDefault(); console.log('連接被點擊'); } return ( <a href="#" onClick={handleClick}> 點我 </a> ); }
實例中 e 是一個合成事件。
使用 React 的時候一般你不須要使用 addEventListener 爲一個已建立的 DOM 元素添加監聽器。你僅僅須要在這個元素初始渲染的時候提供一個監聽器。
當你使用 ES6 class 語法來定義一個組件的時候,事件處理器會成爲類的一個方法。例如,下面的 Toggle 組件渲染一個讓用戶切換開關狀態的按鈕:
class Toggle extends React.Component { constructor(props) { super(props); this.state = {isToggleOn: true}; // 這邊綁定是必要的,這樣 `this` 才能在回調函數中使用 this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })); } render() { return ( <button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'} </button> ); } } ReactDOM.render( <Toggle />, document.getElementById('example') );
你必須謹慎對待 JSX 回調函數中的 this,類的方法默認是不會綁定 this 的。若是你忘記綁定 this.handleClick 並把它傳入 onClick, 當你調用這個函數的時候 this 的值會是 undefined。
這並非 React 的特殊行爲;它是函數如何在 JavaScript 中運行的一部分。一般狀況下,若是你沒有在方法後面添加 () ,例如 onClick={this.handleClick},你應該爲這個方法綁定 this。
若是使用 bind 讓你很煩,這裏有兩種方式能夠解決。若是你正在使用實驗性的屬性初始化器語法,你可使用屬性初始化器來正確的綁定回調函數:
class LoggingButton extends React.Component { // 這個語法確保了 `this` 綁定在 handleClick 中 // 這裏只是一個測試 handleClick = () => { console.log('this is:', this); } render() { return ( <button onClick={this.handleClick}> Click me </button> ); } }
若是你沒有使用屬性初始化器語法,你能夠在回調函數中使用 箭頭函數:
class LoggingButton extends React.Component { handleClick() { console.log('this is:', this); } render() { // 這個語法確保了 `this` 綁定在 handleClick 中 return ( <button onClick={(e) => this.handleClick(e)}> Click me </button> ); } }
使用這個語法有個問題就是每次 LoggingButton 渲染的時候都會建立一個不一樣的回調函數。在大多數狀況下,這沒有問題。然而若是這個回調函數做爲一個屬性值傳入低階組件,這些組件可能會進行額外的從新渲染。咱們一般建議在構造函數中綁定或使用屬性初始化器語法來避免這類性能問題。
一般咱們會爲事件處理程序傳遞額外的參數。例如,如果 id 是你要刪除那一行的 id,如下兩種方式均可以向事件處理程序傳遞參數:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
上述兩種方式是等價的。
上面兩個例子中,參數 e 做爲 React 事件對象將會被做爲第二個參數進行傳遞。經過箭頭函數的方式,事件對象必須顯式的進行傳遞,可是經過 bind 的方式,事件對象以及更多的參數將會被隱式的進行傳遞。
值得注意的是,經過 bind 方式向監聽函數傳參,在類組件中定義的監聽函數,事件對象 e 要排在所傳遞參數的後面,例如:
class Popper extends React.Component{ constructor(){ super(); this.state = {name:'Hello world!'}; } preventPop(name, e){ //事件對象e要放在最後 e.preventDefault(); alert(name); } render(){ return ( <div> <p>hello</p> {/* 經過 bind() 方法傳遞參數。 */} <a href="https://reactjs.org" onClick={this.preventPop.bind(this,this.state.name)}>Click</a> </div> ); } }
在React中,你能夠建立不一樣的組件來封裝各類需求行爲,而後還能夠根據應用的狀態變化只渲染其中的一部分。而後還能夠根據應用的狀態變化只渲染其中的一部分。
先來看兩個組件:
function UserGreeting(props) { return <h1>歡迎回來!</h1>; } function GuestGreeting(props) { return <h1>請先註冊。</h1>; }
咱們將建立一個 Greeting 組件,它會根據用戶是否登陸來顯示其中之一:
function Greeting(props) { const isLoginIn = props.isLoginIn ; if(isLoginIn){ return <GuestGreeting /> } return <GuestGreeting/> } ReactDOM.render( //嘗試修改 isLoginIn={true}; <Greeting isLoginIn={false}/> document.getElementById("example") )
你可使用變量來儲存元素。它能夠幫助你有條件的渲染組件的一部分,而輸出的其餘部分不會更改。
在下面的例子中,咱們將要建立一個名爲 LoginControl 的有狀態的組件。
它會根據當前的狀態來渲染 <LoginButton /> 或 <LogoutButton />,它也將渲染前面例子中的 <Greeting />。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>React 實例</title> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> </head> <body> <div id="example"></div> <script type="text/babel"> class LoginControl extends React.Component { constructor(props) { super(props); this.handleLoginClick = this.handleLoginClick.bind(this); this.handleLogoutClick = this.handleLogoutClick.bind(this); this.state = {isLoggedIn: false}; } handleLoginClick() { this.setState({isLoggedIn: true}); } handleLogoutClick() { this.setState({isLoggedIn: false}); } render() { const isLoggedIn = this.state.isLoggedIn; let button; if (isLoggedIn) { button = <LogoutButton onClick={this.handleLogoutClick} />; } else { button = <LoginButton onClick={this.handleLoginClick} />; } return ( <div> <Greeting isLoggedIn={isLoggedIn} /> {button} </div> ); } } function UserGreeting(props) { return <h1>歡迎回來!</h1>; } function GuestGreeting(props) { return <h1>請先註冊。</h1>; } function Greeting(props) { const isLoggedIn = props.isLoggedIn; if (isLoggedIn) { return <UserGreeting />; } return <GuestGreeting />; } function LoginButton(props) { return ( <button onClick={props.onClick}> 登錄 </button> ); } function LogoutButton(props) { return ( <button onClick={props.onClick}> 退出 </button> ); } ReactDOM.render( <LoginControl />, document.getElementById('example') ); </script> </body> </html>
你能夠經過用花括號包裹代碼在 JSX 中嵌入任何表達式 ,也包括 JavaScript 的邏輯與 &&,它能夠方便地條件渲染一個元素。
function Mailbox(props) { const unreadMessages = props.unreadMessages; return ( <div> <h1>Hello!</h1> {unreadMessages.length > 0 && <h2> 您有 {unreadMessages.length} 條未讀信息。 </h2> } </div> ); } const messages = ['React', 'Re: React', 'Re:Re: React']; ReactDOM.render( <Mailbox unreadMessages={messages} />, document.getElementById('example') );
條件渲染的另外一種方法是使用 JavaScript 的條件運算符:condition ? true : false。
render() { const isLoggedIn = this.state.isLoggedIn; return ( <div> {isLoggedIn ? ( <LogoutButton onClick={this.handleLogoutClick} /> ) : ( <LoginButton onClick={this.handleLoginClick} /> )} </div> ); }
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>React 實例</title> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> <style> button { height: 40px; width: 200px; } .warning { background-color: red; text-align: center; width: 100%; padding: 10px; font-size: 14pt; color: white; } </style> </head> <body> <div id="example"></div> <script type="text/babel"> function WarningBanner(props) { if (!props.warn) { return null; } return ( <div className="warning"> 警告! </div> ); } class Page extends React.Component { constructor(props) { super(props); this.state = {showWarning: true} this.handleToggleClick = this.handleToggleClick.bind(this); } handleToggleClick() { this.setState(prevState => ({ showWarning: !prevState.showWarning })); } render() { return ( <div> <WarningBanner warn={this.state.showWarning} /> <button onClick={this.handleToggleClick}> {this.state.showWarning ? '隱藏' : '顯示'} </button> </div> ); } } ReactDOM.render( <Page />, document.getElementById('example') ); </script> </body> </html>
組件的 render 方法返回 null 並不會影響該組件生命週期方法的回調。例如,componentWillUpdate 和 componentDidUpdate 依然能夠被調用。
咱們可使用 JavaScript 的 map() 方法來建立列表
使用 map() 方法遍歷數組生成了一個 1 到 5 的數字列表:
const numbers = [1,2,3,4,5]; const listItems = numbers.map((item)=> <li>{item}<li/> ) ReactDOM.render( <ul>{listItems}</ul>, document.getElementById('example') );
咱們能夠將以上實例重構成一個組件,組件接收數組參數,每一個列表元素分配一個 key,否則會出現警告 a key should be provided for list items,意思就是須要包含 key:
function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> ); return ( <ul>{listItems}</ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById('example') );
Keys 能夠在 DOM 中的某些元素被增長或刪除的時候幫助 React 識別哪些元素髮生了變化。所以你應當給數組中的每個元素賦予一個肯定的標識。
const numbers = [1, 2, 3, 4, 5]; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> );
一個元素的 key 最好是這個元素在列表中擁有的一個獨一無二的字符串。一般,咱們使用來自數據的 id 做爲元素的 key:
const todoItems = todos.map((todo) => <li key={todo.id}> {todo.text} </li> );
當元素沒有肯定的 id 時,你可使用他的序列號索引 index 做爲 key:
const todoItems = todos.map((todo, index) => // 只有在沒有肯定的 id 時使用 <li key={index}> {todo.text} </li> );
若是列表能夠從新排序,咱們不建議使用索引來進行排序,由於這會致使渲染變得很慢。
元素的 key 只有在它和它的兄弟節點對比時纔有意義。
比方說,若是你提取出一個 ListItem 組件,你應該把 key 保存在數組中的這個 <ListItem /> 元素上,而不是放在 ListItem 組件中的 <li> 元素上。
錯誤示範:
function ListItem(props) { const value = props.value; return ( // 錯啦!你不須要在這裏指定key: <li key={value.toString()}> {value} </li> ); } function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => //錯啦!元素的key應該在這裏指定: <ListItem value={number} /> ); return ( <ul> {listItems} </ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById('example') );
function ListItem(props) { // 對啦!這裏不須要指定key: return <li>{props.value}</li>; } function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => // 又對啦!key應該在數組的上下文中被指定 <ListItem key={number.toString()} value={number} /> ); return ( <ul> {listItems} </ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById('example') );
數組元素中使用的 key 在其兄弟之間應該是獨一無二的。然而,它們不須要是全局惟一的。當咱們生成兩個不一樣的數組時,咱們可使用相同的鍵。
function Blog(props) { const sidebar = ( <ul> {props.posts.map((post) => <li key={post.id}> {post.title} </li> )} </ul> ); const content = props.posts.map((post) => <div key={post.id}> <h3>{post.title}</h3> <p>{post.content}</p> </div> ); return ( <div> {sidebar} <hr /> {content} </div> ); } const posts = [ {id: 1, title: 'Hello World', content: 'Welcome to learning React!'}, {id: 2, title: 'Installation', content: 'You can install React from npm.'} ]; ReactDOM.render( <Blog posts={posts} />, document.getElementById('example') );
key 會做爲給 React 的提示,但不會傳遞給你的組件。若是您的組件中須要使用和 key 相同的值,請將其做爲屬性傳遞:
const content = posts.map((post) => <Post key={post.id} id={post.id} title={post.title} /> ); Post 組件能夠讀出 props.id,可是不能讀出 props.key。
function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => <ListItem key={number.toString()} value={number} /> ); return ( <ul> {listItems} </ul> ); }
JSX 容許在大括號中嵌入任何表達式,因此咱們能夠在 map() 中這樣使用:
function NumberList(props) { const numbers = props.numbers; return ( <ul> {numbers.map((number) => <ListItem key={number.toString()} value={number} /> )} </ul> ); }
設置狀態:setState
替換狀態:replaceState
設置屬性:setProps
替換屬性:replaceProps
強制更新:forceUpdate
獲取DOM節點:findDOMNode
判斷組件掛載狀態:isMounted
setState(object nextState[, function callback])
nextState,將要設置的新狀態,該狀態會和當前的state合併
callback,可選參數,回調函數。該函數會在setState設置成功,且組件從新渲染後調用。
合併nextState和當前state,並從新渲染組件。setState是React事件處理函數中和請求回調函數中觸發UI更新的主要方法。
不能在組件內部經過this.state修改狀態,由於該狀態會在調用setState()後被替換。
setState()並不會當即改變this.state,而是建立一個即將處理的state。setState()並不必定是同步的,爲了提高性能React會批量執行state和DOM渲染。
setState()老是會觸發一次組件重繪,除非在shouldComponentUpdate()中實現了一些條件渲染邏輯。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>React 實例</title> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> </head> <body> <div id="example"></div> <script type="text/babel"> class Counter extends React.Component{ constructor(props) { super(props); this.state = {clickCount: 0}; this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(function(state) { return {clickCount: state.clickCount + 1}; }); } render () { return (<h2 onClick={this.handleClick}>點我!點擊次數爲: {this.state.clickCount}</h2>); } } ReactDOM.render( <Counter />, document.getElementById('example') ); </script> </body> </html>
replaceState(object nextState[, function callback])
nextState,將要設置的新狀態,該狀態會替換當前的state。
callback,可選參數,回調函數。該函數會在replaceState設置成功,且組件從新渲染後調用。
replaceState()方法與setState()相似,可是方法只會保留nextState中狀態,原state不在nextState中的狀態都會被刪除。
setProps(object nextProps[, function callback])
nextProps,將要設置的新屬性,該狀態會和當前的props合併
callback,可選參數,回調函數。該函數會在setProps設置成功,且組件從新渲染後調用。
設置組件屬性,並從新渲染組件。
props至關於組件的數據流,它老是會從父組件向下傳遞至全部的子組件中。當和一個外部的JavaScript應用集成時,咱們可能會須要向組件傳遞數據或通知React.render()組件須要從新渲染,可使用setProps()。
更新組件,我能夠在節點上再次調用React.render(),也能夠經過setProps()方法改變組件屬性,觸發組件從新渲染。
replaceProps(object nextProps[, function callback])
nextProps,將要設置的新屬性,該屬性會替換當前的props。
callback,可選參數,回調函數。該函數會在replaceProps設置成功,且組件從新渲染後調用。
replaceProps()方法與setProps相似,但它會刪除原有 props。
forceUpdate([function callback])
callback,可選參數,回調函數。該函數會在組件render()方法調用後調用。
forceUpdate()方法會使組件調用自身的render()方法從新渲染組件,組件的子組件也會調用本身的render()。可是,組件從新渲染時,依然會讀取this.props和this.state,若是狀態沒有改變,那麼React只會更新DOM。
forceUpdate()方法適用於this.props和this.state以外的組件重繪(如:修改了this.state後),經過該方法通知React須要調用render()
通常來講,應該儘可能避免使用forceUpdate(),而僅從this.props和this.state中讀取狀態並由React觸發render()調用。
DOMElement findDOMNode()
返回值:DOM元素DOMElement
若是組件已經掛載到DOM中,該方法返回對應的本地瀏覽器 DOM 元素。當render返回null 或 false時,this.findDOMNode()也會返回null。從DOM 中讀取值的時候,該方法頗有用,如:獲取表單字段的值和作一些 DOM 操做。
bool isMounted()
返回值:true或false,表示組件是否已掛載到DOM中
isMounted()方法用於判斷組件是否已掛載到DOM中。可使用該方法保證了setState()和forceUpdate()在異步場景下的調用不會出錯。
組件的生命週期可分紅三個狀態:
Mounting:已插入真實 DOM
Updating:正在被從新渲染
Unmounting:已移出真實 DOM
生命週期的方法有:
componentWillMount 在渲染前調用,在客戶端也在服務端。
componentDidMount : 在第一次渲染後調用,只在客戶端。以後組件已經生成了對應的DOM結構,能夠經過this.getDOMNode()來進行訪問。 若是你想和其餘JavaScript框架一塊兒使用,能夠在這個方法中調用setTimeout, setInterval或者發送AJAX請求等操做(防止異步操做阻塞UI)。
componentWillReceiveProps 在組件接收到一個新的 prop (更新後)時被調用。這個方法在初始化render時不會被調用。
shouldComponentUpdate 返回一個布爾值。在組件接收到新的props或者state時被調用。在初始化時或者使用forceUpdate時不被調用。 能夠在你確認不須要更新組件時使用。
componentWillUpdate在組件接收到新的props或者state但尚未render時被調用。在初始化時不會被調用。
componentDidUpdate 在組件完成更新後當即調用。在初始化時不會被調用。
componentWillUnmount在組件從 DOM 中移除以前馬上被調用。
實例在 Hello 組件加載之後,經過 componentDidMount 方法設置一個定時器,每隔100毫秒從新設置組件的透明度,並從新渲染:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>React 實例</title> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> </head> <body> <script type="text/babel"> class Hello extends React.Component { constructor(props) { super(props); this.state = {opacity: 1.0}; } componentDidMount() { this.timer = setInterval(function () { var opacity = this.state.opacity; opacity -= .05; if (opacity < 0.1) { opacity = 1.0; } this.setState({ opacity: opacity }); }.bind(this), 100); } render () { return ( <div style={{opacity: this.state.opacity}}> Hello {this.props.name} </div> ); } } ReactDOM.render( <Hello name="world"/>, document.body ); </script> </body> </html>
React 組件的數據能夠經過 componentDidMount 方法中的 Ajax 來獲取,當從服務端獲取數據時能夠將數據存儲在 state 中,再用 this.setState 方法從新渲染 UI。
當使用異步加載數據時,在組件卸載前使用 componentWillUnmount 來取消未完成的請求。
class UserGist extends React.Component { constructor(props) { super(props); this.state = {username: '', lastGistUrl: ''}; } componentDidMount() { this.serverRequest = $.get(this.props.source, function (result) { var lastGist = result[0]; this.setState({ username: lastGist.owner.login, lastGistUrl: lastGist.html_url }); }.bind(this)); } componentWillUnmount() { this.serverRequest.abort(); } render() { return ( <div> {this.state.username} 用戶最新的 Gist 共享地址: <a href={this.state.lastGistUrl}>{this.state.lastGistUrl}</a> </div> ); } } ReactDOM.render( <UserGist source="https://api.github.com/users/octocat/gists" />, document.getElementById('example') );
以上代碼使用 jQuery 完成 Ajax 請求。
TML 表單元素與 React 中的其餘 DOM 元素有所不一樣,由於表單元素生來就保留一些內部狀態。
在 HTML 當中,像 <input>, <textarea>, 和 <select> 這類表單元素會維持自身狀態,並根據用戶輸入進行更新。但在React中,可變的狀態一般保存在組件的狀態屬性中,而且只能用 setState() 方法進行更新。
在實例中咱們設置了輸入框 input 值 value = {this.state.data}。在輸入框值發生變化時咱們能夠更新 state。咱們可使用 onChange 事件來監聽 input 的變化,並修改 state。
class HelloMessage extends React.Component { constructor(props) { super(props); this.state = {value: 'Hello Runoob!'}; this.handleChange = this.handleChange.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } render() { var value = this.state.value; return <div> <input type="text" value={value} onChange={this.handleChange} /> <h4>{value}</h4> </div>; } } ReactDOM.render( <HelloMessage />, document.getElementById('example') );
上面的代碼將渲染出一個值爲 Hello Runoob! 的 input 元素,並經過 onChange 事件響應更新用戶輸入的值。
在 React 中,不使用 selected 屬性,而在根 select 標籤上用 value 屬性來表示選中項。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>React 實例</title> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> </head> <body> <div id="example"></div> <script type="text/babel"> class FlavorForm extends React.Component { constructor(props) { super(props); this.state = {value: 'coconut'}; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } handleSubmit(event) { alert('Your favorite flavor is: ' + this.state.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> 選擇您最喜歡的網站 <select value={this.state.value} onChange={this.handleChange}> <option value="gg">Google</option> <option value="rn">Runoob</option> <option value="tb">Taobao</option> <option value="fb">Facebook</option> </select> </label> <input type="submit" value="提交" /> </form> ); } } ReactDOM.render( <FlavorForm />, document.getElementById('example') ); </script> </body> </html>
class HelloMessage extends React.Component { constructor(props) { super(props); this.state = {value: 'Hello Runoob!'}; this.handleChange = this.handleChange.bind(this); } handleChange(event) { this.setState({value: 'hello world'}) } render() { var value = this.state.value; return <div> <button onClick={this.handleChange}>點我</button> <h4>{value}</h4> </div>; } } ReactDOM.render( <HelloMessage />, document.getElementById('example') );
當你須要從子組件中更新父組件的 state 時,你須要在父組件經過建立事件句柄 (handleChange) ,並做爲 prop (updateStateProp) 傳遞到你的子組件上。實例以下:
class Content extends React.Component { render() { return <div> <button onClick = {this.props.updateStateProp}>點我</button> <h4>{this.props.myDataProp}</h4> </div> } } class HelloMessage extends React.Component { constructor(props) { super(props); this.state = {value: 'Hello Runoob!'}; this.handleChange = this.handleChange.bind(this); } handleChange(event) { this.setState({value: 'hello world'}) } render() { var value = this.state.value; return <div> <Content myDataProp = {value} updateStateProp = {this.handleChange}></Content> </div>; } } ReactDOM.render( <HelloMessage />, document.getElementById('example') );
React 支持一種很是特殊的屬性 Ref ,你能夠用來綁定到 render() 輸出的任何組件上。
這個特殊的屬性容許你引用 render() 返回的相應的支撐實例( backing instance )。這樣就能夠確保在任什麼時候間老是拿到正確的實例。
綁定一個 ref 屬性到 render 的返回值上:
<input ref="myInput" />
在其它代碼中,經過 this.refs 獲取支撐實例:
var input = this.refs.myInput; var inputValue = input.value; var inputRect = input.getBoundingClientRect();
你能夠經過使用 this 來獲取當前 React 組件,或使用 ref 來獲取組件的引用,實例以下:
class MyComponent extends React.Component { handleClick() { // 使用原生的 DOM API 獲取焦點 this.refs.myInput.focus(); } render() { // 當組件插入到 DOM 後,ref 屬性添加一個組件的引用於到 this.refs return ( <div> <input type="text" ref="myInput" /> <input type="button" value="點我輸入框獲取焦點" onClick={this.handleClick.bind(this)} /> </div> ); } } ReactDOM.render( <MyComponent />, document.getElementById('example') );
咱們獲取了輸入框的支撐實例的引用,子點擊按鈕後輸入框獲取焦點。
咱們也可使用 getDOMNode()方法獲取DOM元素