React
目標
了解組件以及組件的封裝
組件通信
children
defaultProps
React
React.js 是一個幫助你構建頁面 UI 的庫。React.js 將幫助我們將界面分成了各個獨立的小塊帜篇,每一個塊就是組件糙捺,這些組件之間可以組合、嵌套笙隙,就成了我們的頁面洪灯。
一個組件的顯示形態(tài)和行為有可能是由某些數據決定的。而數據是可能發(fā)生改變的竟痰,這時候組件的顯示形態(tài)就會發(fā)生相應的改變签钩。而 React.js 也提供了一種非常高效的方式幫助我們做到了數據和組件顯示形態(tài)之間的同步。
React.js 不是一個框架坏快,它只是一個庫铅檩。它只提供 UI (view)層面的解決方案。在實際的項目當中莽鸿,它并不能解決我們所有的問題昧旨,需要結合其它的庫,例如 Redux祥得、React-router 等來協助提供完整的解決方法兔沃。
模塊化:從 代碼 的角度,去分析問題级及,把我們編程時候的業(yè)務邏輯乒疏,分割到不同的模塊中來進行開發(fā),這樣能夠方便代碼的重用饮焦;
組件化:從 UI 的角度怕吴,去分析問題,把一個頁面县踢,拆分為一些互不相干的小組件转绷,隨著我們項目的開發(fā),我們手里的組件會越來越多硼啤,最后议经,我們如果要實現一個頁面,可能直接把現有的組件拿過來進行拼接丙曙,就能快速得到一個完整的頁面爸业, 這樣方便了UI元素的重用其骄;組件是元素的集合體亏镰。
vue 組件化與 React組件化
1、Vue是如何實現組件化的:.vue 組件模板文件拯爽,瀏覽器不識別這樣的.vue文件索抓,所以,在運行前,會把 .vue 預先編譯成真正的組件逼肯;
template: UI結構
script: 業(yè)務邏輯和數據
style: UI的樣式
2耸黑、React如何實現組件化:在React中實現組件化的時候,根本沒有像 .vue 這樣的模板文件篮幢,而是大刊,直接使用JS代碼的形式,去創(chuàng)建任何你想要的組件三椿;
React中的組件缺菌,都是直接在 js 文件中定義的;
React的組件搜锰,并沒有把一個組件 拆分為 三部分(結構伴郁、樣式、業(yè)務邏輯)蛋叼,而是全部使用JS來實現一個組件的焊傅;(也就是說:結構、樣式狈涮、業(yè)務邏輯是混合在JS里面一起編寫出來的)
React中的核心概念
虛擬DOM(Virtual Document Object Model)
DOM的本質是什么:就是用JS表示的UI元素
-
DOM和虛擬DOM的區(qū)別:
DOM是由瀏覽器中的JS提供功能狐胎,所以我們只能人為的使用 瀏覽器提供的固定的API來操作DOM對象;
虛擬DOM:并不是由瀏覽器提供的薯嗤,而是我們程序員手動模擬實現的顽爹,類似于瀏覽器中的DOM,但是有著本質的區(qū)別骆姐;
為什么要實現虛擬DOM:
什么是React中的虛擬DOM:
虛擬DOM的目的:
DOM DOM
?
?
{
html:
head:
body:{
Navigation:na
content:content
}
?
}
?
class Navigation {
constructor() {
?
}
?
render(){
<img />
<p></p>
}
}
?
var na = new Navigation();```
* Diff算法
* tree diff:新舊DOM樹镜粤,逐層對比的方式,就叫做 tree diff,每當我們從前到后玻褪,把所有層的節(jié)點對比完后肉渴,必然能夠找到那些 需要被更新的元素;
* component diff:在對比每一層的時候带射,組件之間的對比同规,叫做 component diff;當對比組件的時候,如果兩個組件的類型相同窟社,則暫時認為這個組件不需要被更新券勺,如果組件的類型不同,則立即將舊組件移除灿里,新建一個組件关炼,替換到被移除的位置;
* element diff:在組件中匣吊,每個元素之間也要進行對比儒拂,那么寸潦,元素級別的對比,叫做 element diff社痛;
* key:key這個屬性见转,可以把 頁面上的 DOM節(jié)點 和 虛擬DOM中的對象,做一層關聯關系蒜哀;
#### 配置和安裝 React
##### 使用 create-react-app 腳手架安裝 React 開發(fā)環(huán)境
用 React 官網提供的 create-react-app 來搭建非常簡單:
1斩箫、配置安裝 npm
```npm -v```
2、安裝 create-react-app
```npm install -g create-react-app```
3撵儿、創(chuàng)建 React 項目
```//cd 創(chuàng)建項目的目錄
cd 項目路徑
?
//創(chuàng)建
create-react-app 項目名稱```
這條命令會幫我們構建一個叫 react_test 的工程校焦,并且會自動地幫助我們安裝所需要的依賴,現在只需要安靜地等待它安裝完统倒。
4寨典、啟動工程開始項目
```//cd 到項目路徑
cd react_test
?
//npm 啟動工程
npm start```
##### 手動創(chuàng)建 React 開發(fā)環(huán)境
面對復雜的項目, 入門級的構建工具, 是遠遠不夠的, 我們這里從零開始, 用webpack, 手動配置一個獨立的React開發(fā)環(huán)境, 開發(fā)環(huán)境完成后, 支持自動構建, 自動刷新, sass語法 等功能
1、創(chuàng)建項目路徑
```//cd 項目路徑
?
mkdir react_test
?
// 使用 npm 初始化項目
cd react_test
npm init```
2房匆、安裝相關的依賴和軟件包
```//這里主要示例安裝 react react-dom react-scripts
npm install react react-dom react-scripts```
3耸成、配置 package.json 文件和 webpack.config.js文件
## 組件
組件是 React 的核心,組件機制允許你將UI切分成獨立浴鸿、可復用的部分井氢,并針對每個部分單獨去做一定的處理。
#### 組件的好處
1岳链、標記鮮明花竞,容易維護,易與復用
2掸哑、塊狀化結構约急,減少css 的書寫,并且方便擴展
## React 中的組件
### React 構建組件的兩種方式
#### 構造函數構建組件
在React中苗分,構造函數厌蔽,就是一個最基本的組件,如果想要把組件放到頁面中摔癣,可以把 構造函數的名稱奴饮,當作組件的名稱,以 HTML 標簽形式引入頁面中即可择浊。
> 注意:React在解析所有的標簽的時候戴卜,是以標簽的首字母來區(qū)分的,如果標簽的首字母是小寫琢岩,那么就按照普通的 HTML 標簽來解析投剥,如果首字母是大寫,則按照組件的形式去解析渲染
```// 結論:組件的首字母必須是大寫
function HelloMessage(props) {
// 在組件中粘捎,如果想要使用外部傳遞過來的數據薇缅,必須,顯示的在 構造函數參數列表中攒磨,定義 props 屬性來接收泳桦;
// 通過 props 得到的任何數據都是只讀的,不能從新賦值
props.name = '000'
return(
<div>
<h1>這是在Hello組件中定義的元素 --- {props.name}</h1>
</div>
)
}```
#### Class 關鍵字構建組件
```class HelloMessage extends React.Component {
render() {
return <h1>Hello World!</h1>;
}
}
- 區(qū)別
用構造函數創(chuàng)建出來的組件:專業(yè)的名字叫做“無狀態(tài)組件”
用class關鍵字創(chuàng)建出來的組件:專業(yè)的名字叫做“有狀態(tài)組件”
JSX 語法
JSX是一種 JavaScript 的語法擴展娩缰,是 React 官方推出的一套語法規(guī)范灸撰。他可以在 JavaScript 寫 HTML 標簽,JSX 這種語法拼坎,就是為了把HTML模板直接嵌入到JS代碼里面浮毯,這樣就做到了模板和組件關聯,但是 JS 不支持這種包含 HTML 的語法泰鸡,所以需要通過工具將 JSX 編譯輸出成 JS 代碼才能使用债蓝。
npm i babel-preset-react -D
?```
> 1、如要要使用 JSX 語法盛龄,必須先運行 `cnpm i babel-preset-react -D`饰迹,然后再 `.babelrc` 中添加 語法配置;</br> 2余舶、JSX語法的本質:還是以 React.createElement 的形式來實現的啊鸭,并沒有直接把 用戶寫的 HTML代碼,渲染到頁面上匿值;</br> 3赠制、 當 編譯引擎,在編譯JSX代碼的時候挟憔,如果遇到了`<`那么就把它當作 HTML代碼去編譯钟些,如果遇到了 `{}` 就把 花括號內部的代碼當作 普通JS代碼去編譯;</br> 4绊谭、在JSX創(chuàng)建DOM的時候厘唾,所有的節(jié)點,必須有唯一的根元素進行包裹龙誊;
#### JSX 原理
JSX 其實就是 JavaScript 對象,JSX內部在運行的時候抚垃,也是先把 類似于HTML 這樣的標簽代碼, 轉換為了 React.createElement 的形式趟大;也就是說:我們寫了 JSX 這樣的標簽鹤树,也并不是直接把 我們的 HTML 標簽渲染到頁面上,而是先轉換成 React.createElement 這樣的JS代碼逊朽,再渲染到頁面中罕伯;
![image](https://upload-images.jianshu.io/upload_images/20519044-74e477ceea6121ae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
```import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './index.css'
?
class Header extends Component {
render () {
return (
<div>
<h1 className='title'>React 學習</h1>
</div>
)
}
}
?
ReactDOM.render(
<Header />,
document.getElementById('root')
)
?```
```import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './index.css'
?
class Header extends Component {
render () {
return (
React.createElement(
"div",
null,
React.createElement(
"h1",
{ className: 'title' },
"React 學習"
)
)
)
}
}
?
ReactDOM.render(
React.createElement(Header, null),
document.getElementById('root')
);
組件嵌套
返回多個 JSX 元素必須要用一個外層的 JSX 元素把所有內容包裹起來。返回并列多個 JSX 元素是不合法的叽讳。
復用性非常強追他,我們可以把組件的內容封裝好坟募,然后靈活在使用在任何組件內。另外這里要注意的是邑狸,自定義的組件都必須要用大寫字母開頭懈糯,普通的 HTML 標簽都用小寫字母開頭。
組件state
React 把組件看成是一個狀態(tài)機(State Machines)单雾。通過與用戶的交互赚哗,實現不同狀態(tài),然后渲染 UI硅堆,讓用戶界面和數據保持一致屿储。 React 里,只需更新組件的 state渐逃,然后根據新的 state 重新渲染用戶界面(不要操作 DOM)够掠。
?
class CollectButton extends React.Component{
constructor(){
super();
this.state = {
collect:false,
collectPrompt:"未收藏"
}
}
?
handleClick(){
var status = !this.state.collect
var text = status?"收藏":"未收藏";
this.setState({
collect:status,
collectPrompt:text
});
}
?
render(){
return(
<button onClick={()=>{
this.handleClick()
}}>{this.state.collectPrompt}</button>
);
}
}
?
export default CollectButton;```
## 組件通信
#### React Props
state 和 props 主要的區(qū)別在于 props 是不可變的,而 state 可以根據與用戶交互來改變茄菊。這就是為什么有些容器組件需要定義 state 來更新和修改數據祖屏。 而子組件只能通過 props 來傳遞數據。
### 父傳子
子組件定義接受數據屬性名稱 父組件向該屬性賦值
```//父組件
class Father extends React.Component {
constructor() {
super();
this.state = {
屬性名稱:屬性值
}
}
render(){
return({
<子組件 子組件屬性名稱={this.state.屬性名稱}/>
});
}
}
//子組件接受
class Son extends React.Component{
constructor(props){
super();
this.state = props;
}
render(){
return(
<子元素標簽>{this.state.子組件屬性名稱}</子元素標簽>
);
}
}
子傳父
回調函數的方式
class Father extends React.Component {
constructor() {
super();
this.state = {
屬性名稱:屬性值
}
}
// 父組件接受數據定于函數
getData = (需要傳遞給父組件的值)=>{
//拿到子組件傳遞給父組件的值
}
render(){
return({
<子組件 子組件屬性名稱={this.state.屬性名稱} 父組件接受數據函數名稱={this.getData}/>
});
}
}
//子組件接受
class Son extends React.Component{
constructor(props){
super();
this.state = props;
}
handleClick(需要傳遞給父組件的值){
this.props.父組件接受數據函數名稱(需要傳遞給父組件的值)
}
render(){
return(
<子元素標簽 onClick={()=>{
this.handleClick(需要傳遞給父組件的值);
}}>{this.state.子組件屬性名稱}</子元素標簽>
);
}
}
兄弟組件
通過父組件進行數據交互
跨組件通信
數據類型校驗
children
defaultProps
React 獲取dom
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
?
class Index extends Component {
onClick(event){
console.log(event.target.value);
// 第一種方式
var submitObj = document.getElementById('submit');
submitObj.style.color = 'green';
// 第二種方式
ReactDOM.findDOMNode(submitObj).style.color = 'yellow';
// 第三種方式
this.refs.submit.style.color = 'blue';
}
render(){
return (
<div>
<input id='submit' ref='submit'
type='button' value='style'
onClick={this.onClick.bind(this)}/>
</div>
)
}
}```