本篇文章主要講述的是關於react.js的使用,讓大家看看react不是想像中的那麼難。現在就讓我們來看看這篇文章的具體內容吧
1、React全部都是元件化的
##React
是圍繞著可重複使用元件的概念設計的。你定義小組件並將它們組合在一起形成更大的組件。無論大小,所有元件都是可重複使用的,甚至在不同的專案中也是如此。
React
元件最簡單的形式,就是一個普通的JavaScript函數:
function Button (props) {
// 这里返回一个 DOM元素,例如:
return <buttontype="submit">{props.label}</button>;
}
// 将按钮组件呈现给浏览器
ReactDOM.render(<Buttonlabel="Save" />, mountNode)
:編輯上面的程式碼並按Ctrl Enter 鍵執行(譯者註:譯者暫時沒有這個功能,請存取原文使用此功能,下同)
#括號中的button標籤將稍後解釋。現在不要擔心它們。 ReactDOM 也將稍後解釋,但如果你想測試這個例子和所有接下來的例子,上述render 函數是必須的。 (React 將要接管和控制的是ReactDOM.render 的第 2 個參數即目標 DOM元素)。在 jsComplete REPL 中,你可以使用特殊的變數 mountNode。
範例 1的注意事項:
元件名稱首字母大寫,Button。必須要這樣做是因為我們將處理 HTML 元素和 React 元素的混合。小寫名稱是為 HTML 元素保留的。事實上,將 React 元件命名為 “button” 然後你會發現 ReactDOM 會忽略這個函數,只是將其作為一個普通的空 HTML 按鈕來渲染。
每個元件都接收一個屬性列表,就像 HTML元素一樣。在 React 中,這個清單被稱為屬性。雖然你可以隨意將一個函數命名。
在上面 Button函數元件的回傳輸出中,我們奇怪地寫了段落看起來像 HTML 的程式碼。這其實既不是 JavaScript 也不是 HTML,老實說,這甚至不是 React.js。然而它非常流行,以至於成為 React 應用程式中的預設值。這就是所謂的 JSX,這是一個JavaScript 的擴充。 JSX 也是一個折衷方案!繼續嘗試並在上面的函數中傳回其他 HTML 元素,看看它們是如何被支援的(例如,傳回一個文字輸入元素)。 2、 JSX
輸出的是什麼?上面的範例1
可以用沒有JSX的純React.js 寫,如下:
function Button (props) {
return React.createElement(
"button",
{ type: "submit" },
props.label
);
}
// 要使用 Button,你可以这么做
ReactDOM.render(
React.createElement(Button, { label:"Save" }),
mountNode
);
寫React 元件
#在React頂級API 中,createElement 函數是主函數。這是你需要學習的 7 個 API 中的 1 個。 React 的 API 就是這麼小。
就像DOM本身有一個document.createElement 函數來建立一個由標籤名指定的元素一樣,React 的createElement 函數是一個進階函數,有和document.createElement 同樣的功能,但它也可以用來建立一個表示React 元件的元素。當我們使用上面例 2 的按鈕元件時,我們使用的是後者。
不像 document.createElement,React 的 createElement 在接收第二個參數後,接收一個動態參數,它表示所建立元素的子元素。所以 createElement 實際上創建了一個樹。
這裡就是這樣的一個例子:######
const InputForm = React.createElement( "form", { target: "_blank", action:"https://google.com/search" }, React.createElement("p",null, "Enter input and click Search"), React.createElement("input", {className: "big-input" }), React.createElement(Button, { label:"Search" }) ); // InputForm 使用 Button组件,所以我们需要这样做: function Button (props) { return React.createElement( "button", { type: "submit" }, props.label ); } // 然后我们可以通过 .render方法直接使用 InputForm ReactDOM.render(InputForm, mountNode);
例 3:React创建元素的 API
上面例子中的一些事情值得注意:
InputForm 不是一个 React组件;它仅仅是一个 React 元素。这就是为什么我们可以在ReactDOM.render 中直接使用它并且可以在调用时不使用
React.createElement函数在前两个参数后接收了多个参数。从第3个参数开始的参数列表构成了创建元素的子项列表。
我们可以嵌套 React.createElement调用,因为它是 JavaScript。
当这个元素不需要属性时,React.createElement的第二个参数可以为空或者是一个空对象。
我们可以在 React 组件中混合HTML 元素。你可以将 HTML 元素作为内置的 React组件。
React 的 API试图和 DOM API 一样,这就是为什么我们在 input 元素中使用 className 代替 class 的原因。我们都希望如果 React 的 API 成为 DOM API 本身的一部分,因为,你知道,它要好得多。
上述的代码是当你引入 React 库的时候浏览器是怎样理解的。浏览器不会处理任何 JSX 业务。然而,我们更喜欢看到和使用 HTML,而不是那些 createElement 调用(想象一下只使用document.createElement 构建一个网站!)。这就是 JSX 存在的原因。取代上述调用 React.createElement 的方式,我们可以使用一个非常简单类似于HTML 的语法:
const InputForm = <form target="_blank"action="https://google.com/search"> <p>Enter input and clickSearch</p> <inputclassName="big-input" name="q" /> <Buttonlabel="Search" /> </form>; // InputForm “仍然”使用 Button 组件,所以我们也需要这样。 // JXS 或者普通的表单都会这样做 function Button (props) { // 这里返回一个 DOM元素。例如: return <buttontype="submit">{props.label}</button>; } // 然后我们可以直接通过 .render使用 InputForm ReactDOM.render(InputForm, mountNode);
例 4:为什么在 React中 JSX 受欢迎(和例3 相比)
注意上面的几件事:
这不是 HTML 代码。比如,我们仍然可以使用 className 代替 class。
我们仍在考虑怎样让上述的 JavaScript看起来像是 HTML。看一下我在最后是怎样添加的。
我们在上面(例 4)中写的就是 JSX。然而,我们要将编译后的版本(例 3)给浏览器。要做到这一点,我们需要使用一个预处理器将 JSX 版本转换为 React.createElement 版本。
这就是 JSX。这是一种折中的方案,允许我们用类似 HTML 的语法来编写我们的 React 组件,这是一个很好的方法。
“Flux” 在头部作为韵脚来使用,但它也是一个非常受欢迎的应用架构,由 Facebook推广。最出名的是 Redux,Flux 和 React 非常合适。
JSX,可以单独使用,不仅仅适用于 React。
3、 你可以在 JavaScript的任何地方使用 JSX
在 JSX 中,你可以在一对花括号内使用任何 JavaScript 表达式。
const RandomValue = () => <p> { Math.floor(Math.random() * 100)} </p>; // 使用: ReactDOM.render(<RandomValue />,mountNode);
例 5:在 JSX中使用 JavaScript 表达式
任何 JavaScript 表达式可以直接放在花括号中。这相当于在 JavaScript 中插入 ${} 模板。
这是 JSX 内唯一的约束:只有表达式。例如,你不能使用 if 语句,但三元表达式是可以的。
JavaScript 变量也是表达式,所以当组件接受属性列表时(不包括 RandomValue组件,props 是可选择的),你可以在花括号里使用这些属性。我们在上述(例 1)的 Button 组件是这样使用的。
JavaScript 对象也是表达式。有些时候我们在花括号中使用 JavaScript对象,这看起来像是使用了两个花括号,但是在花括号中确实只有一个对象。其中一个用例就是将 CSS 样式对象传递给响应中的特殊样式属性:
const ErrorDisplay = ({message}) => <p style={ { color: 'red',backgroundColor: 'yellow' } }> {message} </p>; // 使用 ReactDOM.render( <ErrorDisplay message="These aren't thedroids you're looking for" />, mountNode );
例 6:一个对象传递特殊的 React样式参数
注意我解构的只是在属性参数之外的信息。这只是 JavaScript。还要注意上面的样式属性是一个特殊的属性(同样,它不是 HTML,它更接近 DOM API)。我们使用一个对象作为样式属性的值并且这个对象定义样式就像我们使用 JavaScript 那样(我们可以这样做)。
你可以在 JSX 中使用 React 元素。因为这也是一个表达式(记住,一个 React 元素只是一个函数调用):
const MaybeError = ({errorMessage}) => <p> {errorMessage &&<ErrorDisplay message={errorMessage} />} </p>; // MaybeError 组件使用 ErrorDisplay组件 const ErrorDisplay = ({message}) => <p style={ { color: 'red',backgroundColor: 'yellow' } }> {message} </p>; // 现在我们使用 MaybeError组件: ReactDOM.render( <MaybeError errorMessage={Math.random() >0.5 ? 'Not good' : ''} />, mountNode );
例 7:一个 React元素是一个可以通过 {} 使用的表达式
上述 MaybeError 组件只会在有errorMessage 传入或者另外有一个空的 p 才会显示 ErrorDisplay 组件。React 认为 {true}、 {false}
{undefined} 和 {null} 是有效元素,不呈现任何内容。
我们也可以在 JSX 中使用所有的JavaScript 的集合方法(map、reduce 、filter、 concat 等)。因为他们返回的也是表达式:
const Doubler = ({value=[1, 2, 3]}) => <p> {value.map(e => e * 2)} </p>; // 使用下面内容 ReactDOM.render(<Doubler />, mountNode);
例 8:在 {}中使用数组
请注意我是如何给出上述 value 属性的默认值的,因为这全部都只是 JavaScript。注意我只是在 p 中输出一个数组表达式。React 是完全可以的。它只会在文本节点中放置每一个加倍的值。
4、 你可以使用 JavaScript类写 React 组件
简单的函数组件非常适合简单的需求,但是有的时候我们需要的更多。React也支持通过使用 JavaScript 类来创建组件。这里 Button 组件(在例 1 中)就是使用类的语法编写的。
class Button extends React.Component { render() { return<button>{this.props.label}</button>; } } // 使用(相同的语法) ReactDOM.render(<Buttonlabel="Save" />, mountNode);
例 9:使用 JavaScript类创建组件
类的语法是非常简单的:定义一个扩展的 React.Component类(另一个你需要学习的 React 的顶级 API)。该类定义了一个单一的实例函数 —— render(),并使函数返回虚拟 DOM 对象。每一次我们使用基于类的 Button 组件(例如,通过 ),React 将从这个基于类的组件中实例化对象,并在 DOM 树中使用该对象。
这就是为什么上面的例子中我们可以在 JSX中使用 this.props.label 渲染输出的原因,因为每一个组件都有一个特殊的称为props 的 实例 属性,这让所有的值传递给该组件时被实例化。
由于我们有一个与组件的单个使用相关联的实例,所以我们可以按照自己的意愿定制该实例。例如,我们可以通过使用常规 JavaScript构造函数来构造它:
class Button extends React.Component { constructor(props) { super(props); this.id = Date.now(); } render() { return <buttonid={this.id}>{this.props.label}</button>; } } // 使用 ReactDOM.render(<Buttonlabel="Save" />, mountNode);
例 10:自定义组件实例
我们也可以定义类的原型并且在任何我们希望的地方使用,包括在返回的 JSX输出的内部:
class Button extends React.Component { clickCounter = 0; handleClick = () => { console.log(`Clicked: ${++this.clickCounter}`); } render() { return ( <button id={this.id}onClick={this.handleClick}> {this.props.label} </button> ); } } // 使用 ReactDOM.render(<Buttonlabel="Save" />, mountNode);
例 11:使用类的属性(通过单击保存按钮进行测试)
注意上述例 11 中的几件事情
handleClick 函数使用 JavaScript 新提出的 class-field syntax 语法。这仍然是 stage-2,但是这是访问组件安装实例(感谢箭头函数)最好的选择(因为很多原因)。然而,你需要使用类似 Babel 的编译器解码为 stage-2(或者仅仅是类字段语法)来让上述代码工作。 jsComplete REPL 有预编译功能。
// 错误:
onClick={this.handleClick()}
// 正确:
onClick={this.handleClick}
5、React中的事件:两个重要的区别
当处理 React 元素中的事件时,我们与 DOM API 的处理方式有两个非常重要的区别:
所有 React 元素属性(包括事件)都使用 camelCase 命名,而不是 lowercase。例如是 onClick 而不是 onclick。
我们将实际的 JavaScript 函数引用传递给事件处理程序,而不是字符串。例如是 onClick={handleClick} 而不是onClick="handleClick"。
React 用自己的对象包装 DOM对象事件以优化事件处理的性能,但是在事件处理程序内部,我们仍然可以访问 DOM对象上所有可以访问的方法。React 将经过包装的事件对象传递给每个调用函数。例如,为了防止表单提交默认提交操作,你可以这样做:
class Form extends React.Component { handleSubmit = (event) => { event.preventDefault(); console.log('Form submitted'); }; render() { return ( <formonSubmit={this.handleSubmit}> <buttontype="submit">Submit</button> </form> ); } } // 使用 ReactDOM.render(<Form />, mountNode);
例 12:使用包装过的对象
6、每一个 React组件都有一个故事:第 1 部分
以下仅适用于类组件(扩展 React.Component)。函数组件有一个稍微不同的故事。
首先,我们定义了一个模板来创建组件中的元素。
然后,我们在某处使用 React。例如,在 render 内部调用其他的组件,或者直接使用 ReactDOM.render。
然后,React 实例化一个对象然后给它设置 props 然后我们可以通过 this.props 访问。这些属性都是我们在第 2 步传入的。
因为这些全部都是 JavaScript,constructor方法将会被调用(如果定义的话)。这是我们称之为的第一个:组件生命周期方法。
接下来 React 计算渲染之后的输出方法(虚拟 DOM 节点)。
因为这是 React 第一次渲染元素,React将会与浏览器连通(代表我们使用 DOM API)来显示元素。这整个过程称为 mounting。
接下来 React 调用另一个生命周期函数,称为 componentDidMount。我们可以这样使用这个方法,例如:在 DOM 上做一些我们现在知道的在浏览器中存在的东西。在此生命周期方法之前,我们使用的 DOM 都是虚拟的。
一些组件的故事到此结束,其他组件得到卸载浏览器 DOM中的各种原因。在后一种情况发生时,会调用另一个生命周期的方法,componentWillUnmount。
任何 mounted 的元素的状态都可能会改变。该元素的父级可能会重新渲染。无论哪种情况,mounted 的元素都可能接收到不同的属性集。React 的魔力就是这儿,我们实际上需要的正是 React 的这一点!在这一点之前,说实话,我们并不需要 React。
组价的故事还在继续,但是在此之前,我们需要理解我所说的这种状态。
7、React组件可以具有私有状态
以下只适用于类组件。我有没有提到有人叫表象而已的部件 dumb?
状态类是任何 React 类组件中的一个特殊字段。React 检测每一个组件状态的变化,但是为了 React 更加有效,我们必须通过 React 的另一个 API 改变状态字段,这就是我们要学习的另一个 API —— this.setState:
class CounterButton extends React.Component { state = { clickCounter: 0, currentTimestamp: new Date(), }; handleClick = () => { this.setState((prevState) => { return { clickCounter:prevState.clickCounter + 1 }; }); }; componentDidMount() { setInterval(() => { this.setState({currentTimestamp: new Date() }) }, 1000); } render() { return ( <p> <buttononClick={this.handleClick}>Click</button> <p>Clicked:{this.state.clickCounter}</p> <p>Time:{this.state.currentTimestamp.toLocaleString()}</p> </p> ); } } // 使用 ReactDOM.render(<CounterButton />,mountNode);
例 13:setState的 API
这可能是最重要的一个例子因为这将是你完全理解 React基础知识的方式。这个例子之后,还有一些小事情需要学习,但从那时起主要是你和你的 JavaScript 技能。
让我们来看一下例 13,从类开始,总共有两个,一个是一个初始化的有初始值为 0 的 clickCounter 对象和一个从 new Date() 开始的 currentTimestamp。
另一个类是 handleClick 函数,在渲染方法中我们给按钮元素传入 onClick 事件。通过使用 setState 的 handleClick 方法修改了组件的实例状态。要注意到这一点。
另一个我们修改状态的地方是在一个内部的定时器,开始在内部的componentDidMount生命周期方法。它每秒钟调用一次并且执行另一个函数调用this.setState。
在渲染方法中,我们使用具有正常读语法的状态上的两个属性(没有专门的 API)。
现在,注意我们更新状态使用两种不同的方式:
通过传入一个函数然后返回一个对象。我们在 handleClick函数内部这样做。
通过传入一个正则对象,我们在在区间回调中这样做。
这两种方式都是可以接受的,但是当你同时读写状态时,第一种方法是首选的(我们这样做)。在区间回调中,我们只向状态写入而不读它。当有问题时,总是使用第一个函数作为参数语法。伴随着竞争条件这更安全,因为 setstate实际上是一个异步方法。
我們應該怎麼更新狀態呢?我們傳回一個有我們想要更新的值的物件。請注意,在呼叫setState時,我們全部都從狀態中傳入一個屬性或全都不。這完全是可以的因為setState 實際上合併了你通過它(返回值的函數參數)與現有的狀態,所以,沒有指定一個屬性在調用setState 時意味著我們不希望改變屬性(但不刪除它) 。
8、React將要反應
React 的名字是從狀態改變的反應中得來的(雖然沒有反應,但也是在一個時間表中)。這裡有一個笑話,React應該要命名為Schedule!
然而,當任何元件的狀態被更新時,我們用肉眼觀察到的是對該更新的反應,並自動反映了瀏覽器DOM中的更新(如果需要的話)。
將渲染函數的輸入視為兩種:
透過父元素傳入的屬性
以及可以隨時更新的內部私有狀態
當渲染函數的輸入改變時,輸出可能也會改變。
React 儲存了渲染的歷史記錄,當它看到一個渲染與前一個不同時,它將計算它們之間的差異,並將其有效地轉換為在DOM中執行的實際DOM 操作。
9、 React是你的程式碼
你可以將React 看成是我們用來與瀏覽器通訊的代理程式。以上面的目前時間戳顯示為例。取代每一秒我們都需要手動去瀏覽器呼叫 DOM API 操作來尋找和更新 p#timestamp 元素,我們只是改變元件的狀態屬性,React 所做的工作代表我們與瀏覽器的通訊。我相信這就是為什麼 React 這麼受歡迎的真正原因;我們只是不喜歡和瀏覽器先生談話(以及它所說的 DOM 語言的很多方言),並且 React 自願傳遞給我們,免費的!
10、 每個React元件都有一個故事:第2 部分
現在我們知道了一個組件的狀態,當該狀態改變的時候,我們來了解一下關於這個過程的最後幾個概念。
當元件的狀態被更新時,或者它的父行程決定更改它傳遞給元件的屬性時,元件可能需要重新渲染。
如果後者發生,React 會呼叫另一個生命週期方法:componentWillReceiveProps。
如果狀態物件或傳遞的屬性改變了,React有一個重要的決定要做:元件是否應該在 DOM 中更新?這就是為什麼它呼叫另一個重要的生命週期方法shouldComponentUpdate 的原因 。此方法是一個實際問題,因此,如果需要自行定製或最佳化渲染過程,則必須透過傳回 true 或 false 來回答這個問題。
如果沒有自訂 shouldComponentUpdate,React 的預設事件在大多數情況下都能處理的很好。
首先,這個時候會呼叫另一個生命週期的方法:componentWillUpdate。然後,React 將計算新渲染過的輸出,並將其與最後渲染的輸出進行比較。
如果渲染過的輸出和先前的相同,React不進行處理(不需要和瀏覽器先生對話)。
如果有不同的地方,React 將不同傳達給瀏覽器,就像我們之前看到的那樣。
在任何情況下,一旦一個更新程式發生了,無論以何種方式(即使有相同的輸出),React會呼叫最後的生命週期方法:componentDidUpdate。
生命週期方法是逃生艙口。如果你沒有做什麼特別的事情,你可以在沒有它們的情況下創建完整的應用程式。它們非常方便地分析應用程式中正在發生的事情,並進一步優化React更新的效能
本篇文章到這就結束了(想看更多就到PHP中文網 React使用手冊欄位中學習),有問題的可以在下方留言提問。
以上是React.js怎麼使用? react.js的簡單使用方法介紹(附實例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!