手挽手帶你學React入門第一期,帶你熟悉React的語法規則,消除對JSX的恐懼感,由於現在開發中都是使用ES6語法開發React,所以這次也使用ES6的模式進行教學,如果大家對ES6不熟悉的話,先去看看class相關內容吧,這裡我也慢慢帶大家一步一步學會React。
視訊教程
視訊大家移步我的個人部落格:www.henrongyi.top,掘金放不上來呢
什麼是React
React是Facebook的一群變態們開發的一個特別牛X的框架。它實際上是一個虛擬DOM,然後在這個DOM中,要用什麼元件就能飛速載入進來,不要的時候,馬上給刪咯(實際上就是個前端框架,都是這麼個意思,VUE,NG都是,只不過他們的資料流向不同而已,React區別就在於,單向資料流。),React 扮演著 MVC 結構中 V 的角色,後面我會用到基於FLUX架構的Redux讓我們的整個專案變成MVC架構。總之,React也是hie牛X的。
React的好處都有啥
React是一款非常牛X的前端框架,它的衍生物React-Native可以讓你開發接近原生體驗的NativeApp,它適合的範圍相當廣泛,前端,後端,手機端,都有很好的相容性。總而言之,hie牛X。
React基礎入門
現在的開發中React專案實際上都是使用ES6語法來編寫,並且,我們現在有很多成熟的腳手架可以使用(create-react-app,dva等),不過國際慣例,我們要從最基礎的用法開始編寫。我們採用ES6寫法來進行教學,同時使用webpack工具,這裡會用到很多相關配置,大家可以在這個過程中體驗ES6的精妙。
開始HelloWord
配置基礎webpack環境
這裡大家可以不去深入理解,先跟著我一步一步配置出來
開始之前,大家可以去官網:reactjs.org/ 下載最新的React(當前版本v16.7.0) 中文地址:react.docschina.org/
由於我們不使用腳手架,所以我們需要先建立我們自己的webpack包,第一步
mkdir helloReact
cd helloReact
複製程式碼
首先大家命令列輸入
webpack v
複製程式碼
如果正常出現版本號 並且是 3.6.0版本,那麼我們就可以按照教程繼續走下去了 如果沒有的話 那麼我們就需要命令列繼續
cnpm i webpack@3.6.0 -S -g
複製程式碼
到這裡應該可以正常使用webpack了
接下來 我們命令列輸入
npm init -y // 這實際上是 初始化一個專案 並且全部預設 當然如果你想看看裡面有啥的話 就把-y拿掉就好了
npm i //這裡是把webpack依賴安裝到本包內部
npm i webpack-dev-server@2.11.1 --save-dev //安裝本地執行伺服器
npm i webpack-cli --save-dev //依賴腳手架
複製程式碼
執行完成以後,我們會得到一個package.json檔案 開啟看看
{
"dependencies": {
"webpack": "^3.6.0" //依賴包和版本
},
"name": "helloreact", //專案名
"version": "1.0.0", // 版本號
"main": "index.js", //入口檔案
"scripts": { //npm run 加這裡面的key就可以快速執行命令列
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "", // 作者
"license": "ISC",
"description": "" //簡介
}
複製程式碼
這裡面實際上是我們專案的一些基礎資訊
我們需要自己配置webpack和babel 這裡我們需要建立兩個檔案 這裡面我們要設定入口檔案,輸出檔案,babel,webpackServer等等,這裡不做太詳細的介紹 大家可以直接複製程式碼,後面可能會開專門的webpack視訊課程。 小小的介紹一下這些都是幹什麼用的 babel-core 呼叫Babel的API進行轉碼 babel-loader babel-preset-es2015 用於解析 ES6 babel-preset-react 用於解析 JSX babel-preset-stage-0 用於解析 ES7 提案 命令列輸入
npm install --save-dev babel-core babel-loader@7.1.5 babel-preset-es2015 babel-preset-react babel-preset-stage-0
複製程式碼
接下來我們在helloReact 資料夾中建立 webpack.config.js 檔案
// webpack.config.js 直接複製即可
const path = require("path");
module.exports = {
/*入口*/
entry: path.join(__dirname, 'src/index.js'),
/*輸出到dist資料夾,輸出檔名字為bundle.js*/
output: {
path: path.join(__dirname, './dist'),
filename: 'bundle.js'
},
/*src資料夾下面的以.js結尾的檔案,要使用babel解析*/
/*cacheDirectory是用來快取編譯結果,下次編譯加速*/
module: {
rules: [{
test: /\.js$/,
use: ['babel-loader?cacheDirectory=true'],
include: path.join(__dirname, 'src')
}]
},
plugins : [],
devServer : {
disableHostCheck: true,
inline: true,
port:9527,
contentBase: path.join(__dirname, "/"),
}
}
複製程式碼
接下來我們在helloReact 資料夾中建立 .babelrc 檔案
{
"presets": [
"es2015",
"react",
"stage-0"
],
"plugins": []
}
複製程式碼
然後我們在package.json檔案的script中新增
//package.json
{
"dependencies": {
"webpack": "^3.6.0"
},
"name": "helloreact",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"server": "webpack-dev-server",
"build": "webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^2.11.1"
}
}
複製程式碼
這些配置完了,我們就在helloReact mkdir src 並且在src中建立 index.js檔案 在 根路徑 helloReact下建立 index.html 因為這裡我們要用到 react了 所以需要命令列安裝一下 react
cnpm install --save react react-dom
複製程式碼
html檔案如下
<!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>Document</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="bundle.js"></script>
</html>
複製程式碼
js 檔案如下
import React from 'react'; //es6 引入react
import ReactDom from 'react-dom'; //es6 引入reactReacrDom
ReactDom.render( //ReactDom渲染<div>hello React</div> 這個html標籤 到 id='app'這個標籤下
<div>Hello React!</div>, document.getElementById('app'));
複製程式碼
一切都寫完了 我們執行服務 npm run server 來看一眼
如果你看到螢幕顯示出 Hello React! 那麼恭喜你 環境配置完了 我們們可以開始學習 React 了
如果你配置了半天還沒配置成功
到我的github下載程式碼吧。。。github.com/piexlmax/he…
React的Hello World
我們看到上面的程式碼
import React from 'react'; //es6 引入react
import ReactDom from 'react-dom'; //es6 引入reactReacrDom
ReactDom.render( //ReactDom渲染<div>hello React</div> 這個html標籤 到 id='app'這個標籤下
<div>Hello React!</div>, document.getElementById('app'));
複製程式碼
這是一個簡單的渲染 是不是根本看不到 React的元件化模式呢?
所以這裡 我們需要寫一個根部元件,以後的元件都放跟元件裡面,這個JS就理所當然成了一個入口檔案了
這裡 我們在 src下面建立一個app.js檔案
app.js
import React, {Component} from 'react';
// 這裡我們引入 react 和 react的Component
// 建立 Hello 這個class(class屬於ES6內容) 然後繼承 Component 我們就成功地建立了一個 react元件
export default class App extends Component {
render() {
return (
<div>
Hello,World!
</div>
)
}
}
複製程式碼
index.js 我們需要改寫為這樣
import React from 'react';
import ReactDom from 'react-dom';
import App from './app.js' //引入我們的根元件App
ReactDom.render( //把App 渲染到 id=app的dom中
<App/>, document.getElementById('app'));
複製程式碼
到這裡 我們已經實現了一個真正意義上的Hello World了!
傳說中的jsx
開始玩React了,那就必須要用到jsx語法,什麼是jsx呢?
JSX是一種JavaScript的語法擴充套件。JSX與模板語言相似,但它具有JavaScript的全部功能。JSX會被編譯為React.createElement()方法呼叫,將返回名為“React elements”的普通JavaScript物件。
上面程式碼裡我們看到 我們的html實際上是在js中的render函式中書寫的,是一個React擴充套件,允許我們編寫看起來像 HTML的JavaScript 。
切記 自定義元件一定要大寫字母開頭 return加括號 並且左括號要和return在同一行 只能return一個標籤,其餘內容都要在這個標籤內部
export default class App extends Component {
render() {
return (
<div>
Hello,World!
</div>
)
}
}
複製程式碼
像是這樣一段程式碼,實際上我們真正使用的時候,已經經過了一次編譯,編譯過後它長這樣。
export default class App extends React.Component {
render() {
return (
React.createElement(
'div',
'Hello,World!'
)
);
}
}
複製程式碼
下面的這一段程式碼是不是就不容易理解了?這實際上是js可以幫我們去書寫dom的程式碼。 在React中JSX你可以理解為我們可以在js中寫HTML程式碼了 更通俗一點
export default class App extends Component {
// 方法 生命週期 state 等
render() {
return (
// HTML模板
)
}
}
複製程式碼
React的基本使用方法
state
我們之前學過VUE,VUE中每個元件的資料存在自己的data中,那麼在React中,資料存在哪裡呢?沒錯狀態state中。 由於我們這裡用的是ES6的class 所以 我們子類constructor中必須先呼叫super才能引用this。 所以我們這裡應該這麼寫state
export default class App extends Component {
constructor(){
super()
this.state={
hello:"hello World"
}
}
render() {
return (
<div>
{this.state.hello}
</div>
)
}
}
複製程式碼
這裡我們可以看出,我們想要在render中使用js 就需要用一個{} 這裡面的內容同樣可以書寫簡單的js表示式。
rander函式中使用state和JS表示式
export default class App extends Component {
constructor(){
super()
this.state={
hello:"hello World"
}
}
render() {
return (
<div>
<ul>
<li>展示state中的資料:{this.state.hello}</li>
<li>三元,短路等,這裡用三元示例{this.state.hello?"存在hello":"不存在hello"}</li>
<li>簡單計算{1+1}</li>
<li>JS表示式{Math.floor(Math.random()*10)}</li>
</ul>
</div>
)
}
}
複製程式碼
方法的宣告以及修改state
聲名方法我們有兩種模式,一種是直接書寫 方法名(引數){程式碼段}模式,這樣的模式在呼叫的時候需要手動bind(this) 還有一種就是使用es6的箭頭函式,讓其this指向自身
修改state資料需要呼叫 this.setState()方法 內部接收一個物件 要修改哪個key 就在物件內部填寫這個key,並且後面的值就是你要修改的內容,如果,key在state中不存在,則會在state中增加這個key
export default class App extends Component {
constructor(){
super()
this.state={
hello:"hello World"
}
}
bye(){
this.setState({
hello:"bye world"
})
}
byebye=()=>{
this.setState({
helloo:"bye world"
})
}
render() {
return (
<div>
<ul>
<li>非箭頭函式:{this.state.hello}</li>
<li>箭頭函式:{this.state.helloo}</li>
</ul>
<button onClick={this.bye.bind(this)}>無箭頭</button>
{/* 這裡使用bind來繫結this 如果傳參的話this.bye.bind(this,引數1,引數2) */}
<button onClick={()=>{this.byebye()}}>箭頭函式</button>
{/* 這裡是箭頭函式的預設屬性來搞定了this問題 如果傳參的話()=>{this.byebye(引數1,引數2)*/}}
</div>
)
}
}
複製程式碼
這裡需要注意,只有觸發了state的變化,才會導致元件的重新渲染
迴圈語句,條件語句的使用
大家在vue中使用v-for 就能夠完成迴圈生成元件這樣的操作了,在react中我們應該怎麼做呢?
迴圈語句 我們說過 jsx 裡面是可以自由自在地使用js的 一般情況下我們使用map迴圈
在迴圈的時候,每一個return出來的標籤都需要新增 key={鍵值} “鍵值”是建立元素陣列時需要包含的特殊字串屬性。鍵值可以幫助React識別哪些元素被更改,新增或刪除。因此你應當給陣列中的每一個元素賦予一個確定的標識
export default class App extends Component {
constructor(){
super()
this.state={
arr:[{text:"qm"},{text:"奇淼"},{text:"大帥逼"}]
}
}
render() {
return (
<div>
{/* 我們說過 jsx 裡面是可以自由自在地使用js的 這裡我們來玩一個迴圈生成li */}
<ul>
{this.state.arr.map((item,key)=>{
return(<li key={key}>{item.text}</li>)
})}
</ul>
</div>
)
}
}
複製程式碼
判斷語句 判斷語句我們一般使用短路表示式 三元表示式來展示我們想要展示的內容,但是如果需要複雜的條件判斷,那麼我們最好是寫一個自執行函式,然後再函式體內你就可以為所欲為了,記住一定要return你想要得到的dom標籤。
export default class App extends Component {
constructor(){
super()
this.state={
arr:[{text:"qm"},{text:"奇淼"},{text:"大帥逼"}]
}
}
render() {
return (
<div>
{/*簡單的三元和短路例項*/}
{this.state.arr.length==3?<div>我是三元判斷的三個</div>:<div>我是三元判斷的不是三個</div>}
{this.state.arr.length==3&&<div>我是短路判斷的三個</div>}
{/* 我們說過 jsx 內部支援簡單的表示式 如果我們使用 if條件句的話 會導致報錯*/}
{/*
if(this.state.arr.length==3){
return(<div>有三個</div>)
}
*/}
{/* 我們說過 jsx 這已經是js程式碼段而不是簡單語句了,我們簡單判斷可以使用三元或者短路表示式來進行,但是複雜一點的,我們可以使用如下方法*/}
{(()=>{
if(this.state.arr.length==3){
return(<div>陣列有三個元素</div>)
}else{
return(<div>陣列有不是三個元素</div>)
}
})()}
</div>
)
}
}
複製程式碼
迴圈判斷巢狀 有些時候我們需要根據特定條件去迴圈,然後渲染出篩選過後的資料,這時候就需要迴圈和判斷巢狀使用了,其實也相當簡單,我們的迴圈實際上是一個簡單的js表示式,內部的function中可以隨意書寫js,記得return就好了
export default class App extends Component {
constructor(){
super()
this.state={
arr:[{text:"qm"},{text:"奇淼"},{text:"大帥逼"}]
}
}
render() {
return (
<div>
{this.state.arr.map((item,key)=>{
if(key%2==0){
return(<div key={key}>我是可以餘2的{item.text}</div>)
}else{
return(<div key={key}>我是不能餘2的{item.text}</div>)
}
})}
</div>
)
}
}
複製程式碼
獲取DOM(Refs)
有些時候我們不得不去操作DOM,那這時候 我們需要用到 ref 屬性
React支援一個可以附加到任何元件的特殊屬性ref。ref屬性可以是一個字串或一個回撥函式。當ref屬性是一個回撥函式時,函式接收底層DOM元素或類例項(取決於元素的型別)作為引數。這使你可以直接訪問DOM元素或元件例項。
另外這裡應該注意 不要過度使用 Refs。
export default class App extends Component {
constructor(){
super()
this.state={
arr:[{text:"qm"},{text:"奇淼"},{text:"大帥逼"}]
}
}
render() {
return (
<div>
{this.state.arr.map((item,key)=>{
if(key%2==0){
return(<div ref="link" key={key}>我是可以餘2的{item.text}</div>)
{/* 這樣我們可以通過 this.refs.link 獲取到這個dom 並且操作dom了 */}
}else{
return(<div key={key}>我是不能餘2的{item.text}</div>)
}
})}
</div>
)
}
}
複製程式碼
總結
到這裡我們已經學會了React的基本元件內部的操作了,React相對於Vue來說更加靈活,但是唯一的缺點是資料流是單向的,必須通過setState來修改,對於處理表單來說會有些麻煩,不過有些UI框架,外掛幫我們處理了這些大麻煩。寫寫玩玩吧React還是比較簡單的。