一、React項目起步配置
文檔:https://reactjs.org/docs/hello-world.html
2013年被開源,2014年在中國徹底火爆。
React是CMD架構,現階段需要webpack打包
npm install -g webpack@4.9.1
必須安裝以下三個依賴:
npm install --save-dev babel-core babel-loader babel-preset-env
React采用jsx語法,JSX語法是什么?
就是全球唯一標准的JavaScript和XHTML結合開發最優雅的語法。
瀏覽器不識別JSX語法,所以需要babel將JSX語法翻譯,babel要裝一個新的preset
npm install --save-dev babel-preset-react
安裝完依賴,修改webpack.congif.js文件中的preset配置:
const path = require('path'); module.exports = { entry: "./www/app/main", output : { path: path.resolve(__dirname, "www/dist"), filename : "bundle.js", }, watch:true, mode : "development", module: { rules: [ { test: /\.js?$/, include: [path.resolve(__dirname, "www/app")], exclude: [path.resolve(__dirname, "node_modules")], loader : "babel-loader", options: { presets: ["env","react"] }, //要翻譯的語法 } ] } }
還要安裝react和react-dom包:
npm install --save react react-dom
react是核心庫
react-dom提供了與DOM操作的功能庫
注意:項目文件夾名字千萬不要叫react,很坑。
在index.html上放“掛載點”的盒子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> </head> <body> <div id="app"></div> </body> <script type="text/javascript" src="dist/bundle.js"></script> </html>
app/main.js

import React from "react"; import ReactDOM from "react-dom"; ReactDOM.render( <div> <h1>你好,我是react,來自Facebook公司</h1> </div>, document.getElementById('app') );
運行webpack,直接打開頁面:
React是所有react項目的入口
React-dom負責react Element添加到HTML頁面的掛載點上
react-dom 這個包提供了你的app最高等級的API,提供了元素的掛載和上樹的方法
render() 接收兩個參數,第一個參數是react元素,第二個參數是掛載點,用來讓react元素進行掛載。
Vue在寫實例,而React在寫類(構造函數)。
二、組件
組件叫“component”,就是HTML、CSS和JS行為的一個封裝。
Vue中的組件是一個.vue文件(其實是普通的JSON對象),React中,組件是一個類(構造函數)。
2.1類式組件
創建App.js文件,這是一個組件,必須按照要求寫標准殼,這個殼我們叫rcc殼“react class component”,react的類式組件:
import React from "react"; // 默認暴露一個構造函數(類組件) export default class App extends React.Component{ constructor(){ super(); } render(){ return <div> <h1>我是App組件!</h1> </div> } }
注意:
1)這個文件的默認暴露就是一個類,這個類的類名必須和文件名相同。 2)文件名和類名的首字母必須大寫!React中組件的合法名字首字母必須是大寫字母。 3)這個類必須繼承自React.Component類,也就是說,rcc殼必須是extends React.Component的寫法。 4)這個類必須有構造器constructor,構造器里面必須調用超類的構造器,super(); 5)這個類必須有render函數,render函數中必須return一個jsx對象。而且這個jsx對象必須被唯一的標簽包裹。
在main.js主文件中引入組件,然后用自定義標簽:
import React from "react"; import ReactDOM from "react-dom"; // 引入組件 import App from "./App.js"; ReactDOM.render( <div> <App></App> <h1>你好,我是react,來自Facebook公司</h1> </div>, document.getElementById("app") );
注意:
引入的組件必須路徑以./開頭
組件要使用,就將這個組件的名字(類名、文件名)進行標簽化即可
原理就是這個App類在被實例化。
因為類的名字是大寫字母,所以所有的自定義組件標簽名字一定是大寫字母開頭的
在react中,所有以大寫字母開頭的都是組件,而不是標簽。
ReactDOM.render(根jsx,根的掛載點)
ReactDOM只能出現一次,但是非常厲害,可以和HTML結合
jsx,現在一律在js文件夾中開發,並不是傳統放html開發
HTML、CSS、JS都被構建到bundle.js文件夾中。
安裝以下插件,輸入rcc即可快速生成一個組件的語法:
2.2組件可以多層嵌套
main.js文件中引入App.js組件,App組件里面的render函數還可以引入其他組件。
components/Child.js
import React from "react"; export default class Child extends React.Component { constructor() { super(); } render() { return <div> <h1>我是Child子組件!</h1> </div> } }
App父組件中引入:
import React from "react"; import Child from "./components/Child"; // 默認暴露一個構造函數(類組件) export default class App extends React.Component { constructor() { super(); } render() { return <div> <h1>我是App組件!</h1> <Child></Child> <Child></Child> <Child></Child> </div> } }
簡單的說:在react中做一個組件:
第一步:創建一個類並暴露
第二步:引入這個類,然后用這個類的類名當做組件的標簽(實例化)
2.3函數式組件
一個函數,如果是大寫字母開頭,並且return一個React Element就是一個組件。
比如App.js組件中,創建一個Child1的函數,這個函數直接返回JSX語法的React Element,此時這個函數就是組件,這個函數直接成為自定義標簽,就可以用了。
import React from "react"; import Child from "./components/Child"; // 默認暴露一個構造函數(類組件) //定義一個自定義的函數組件 const Child1 = ()=> <div> <h1>我是Child1函數式組件!</h1> </div> export default class App extends React.Component { constructor() { super(); } render() { return <div> <h1>我是App組件!</h1> <Child></Child> <Child1></Child1> </div> } }
注意:
1)render是一個函數,所以函數里面當然可以定義另一個函數。我們用const來定義一個箭頭函數,這個箭頭函數的名字,必須首字母大寫。react中所有標簽名字是首字母大寫的,將被判定為我們自己的組件。
2)這個函數里面return了一個jsx對象,注意,不要加引號。初學者會有很多不適。
3)這個組件也是通過“標簽”的形式來上樹的!
4)函數式組件比類組件差很多功能很多,后面會說。
5)至於什么時候用什么組件、圓括號中能不能傳入參數,后面會說。
函數式組件有個缺點,沒有state,沒有生命周期。
三、JSX語法
所有對React不適應,都是JSX語法造成的,JSX語法淡化了JS和HTML之間的“邊界”。
3.1標簽必須合理嵌套
錯誤的:
import React from "react"; import ReactDOM from "react-dom"; // 引入組件 import App from "./App.js" ReactDOM.render( <App></App> <App></App> <App></App> , document.getElementById('app') );
有多個組件,必須有一個標簽包裹所有組件:
import React from "react"; import ReactDOM from "react-dom"; // 引入組件 import App from "./App.js" ReactDOM.render( <div> <App></App> <App></App> <App></App> </div> , document.getElementById('app') );
比如table不能直接嵌套tr,必須要有tbody
import React from "react"; export default class App extends React.Component { constructor() { super(); } render() { return <div> <table> <tbody> <tr> <td>1</td> <td>2</td> </tr> </tbody> </table> </div> } }
比如這樣也是錯誤的:
<p><div>111</div></p>
3.2 return不能換行
return后面直接跟着div,不能換行
如果想換行,必須加圓括號包裹。
import React from "react"; export default class App extends React.Component { constructor() { super(); } render() { return ( <div> <h1>我是App組件</h1> </div> ) } }
3.3標簽必須嚴格封閉
因為jsx語法被babel-loader翻譯(babel-perset-react),所以標簽必須嚴格封閉,否則翻譯會報錯。
錯誤的: <br> <hr> 正確的: <br/> <hr/> 錯誤的: <input type="text"> 正確的: <input type="text" />
3.4所有的類名必須用className表示
因為JS中class是關鍵字,所以類名必須用className
錯誤的
<div class="box"></div>
正確的:
<div className="box"></div>
for要用htmlFor代替:
錯誤的: <label for=""></label> 正確的: <label htmlFor=""></label>
3.5插值基礎(重點)
可以在jsx內部,用單個“{}”大括號進行一些js表達式的插入,我們叫做插值。
{} 只能出現在React element中,簡化了連字符串工作。
import React from "react"; export default class App extends React.Component { constructor() { super(); } render() { const year = 10000; const pingfang = (n)=>{ return n * n } const arr = [1000,2000,3000,4000] return <div> <h1>{5000 * 2}年</h1> <h1>{year}年</h1> <h1>{pingfang(100)}年</h1> <h1>{arr.reduce((a,b)=>a + b)}年</h1> <h1>{parseInt(Math.random() * 100)}年</h1> <h1>{3 > 8 ? 10000 : 1}年</h1> </div> } }
不能出現的語法:
不能定義變量:
<h1>{var a = 100}</h1>
不能定義函數:
<h1>{function name(){}}</h1>
應該在return之前定義:
render() { const pingfang = (n)=> n * n return ( <div> <h1>我愛你{pingfang(100)}年</h1> </div> ) }
不能出現for循環、if語句、while、do語句:
<h1>{for(var i = 0;i < 100;i++){}}</h1>
JSX不能出現對象(JSON)。
render() { const obj = {"a":100,"b":200} return ( <div> <h1>{obj}</h1> </div> ) }
此時會報錯,如果要在頁面顯示JSON,應該:
render() { const obj = {"a":100,"b":200} return ( <div> <h1>{JSON.stringify(obj)}</h1> </div> ) }
3.6插值高級
JSX表達式不能出現引號中,比如有一個變量
render() { const picUrl = "baby1.jpg" return <div> <img src="images/{picUrl}.jpg" /> </div> }
正確的應該先寫在外層的{}:
render() { const picUrl = "baby1"; const tip = '這是黃曉明老婆'; const url = 'http://www.baidu.com/' return <div> <img src={"images/" + picUrl + ".jpg"} /> <img src={`images/${picUrl}.jpg`} title={tip} /> <a href={url}>去百度</a> </div> }
內嵌樣式要求這樣的語法插值:
style后面直接跟着{{}},沒有引號,{{}}中是JSON,所有的屬性名都是駝峰命名法:
<div style={{"width":"100px","height":"100px","backgroundColor":"red"}}></div>
react的程序,可以進行合理的換行
<div style={{ "width":"100px", "height":"100px", "backgroundColor":"red" }}> </div>
3.7 jsx中數組內容會被自動展開(重點)
此時你心里可能有一萬個草泥馬,這是什么鬼,數組怎么能不加引號呢?因為是JSX語法規定。
import React from "react"; export default class App extends React.Component { constructor() { super(); } render() { const arr = [ <li key="0">牛奶</li>, <li key="1">咖啡</li>, <li key="2">奶茶</li>, <li key="3">可樂</li> ] return <div> <ul> {arr} </ul> </div> } }
只要你在{}放一個數組,此時這個數組不用循環了,就會自動被展開。
所有的數組元素,必須加上key屬性,否則報錯
注意:
數組有4項,每項都是jsx元素,不需要加引號
每項必須要有不同的key屬性,這是react要求的
數組直接{arr}就可以了,也不需要寫循環遍歷語句。
數據和DOM怎么進行模板的循環:
arr數組中,沒有任何的標簽,只是數據:此時就要在{}中用map來映射一個新的數組

import React from "react"; export default class App extends React.Component { constructor() { super(); } render() { const arr = ["牛奶","咖啡","奶茶","可樂"] return <div> <ul> {arr.map((item,index)=>{ return <li key={index}>{item}</li> })} </ul> </div> } }
映射出一個表格:

import React from "react"; export default class App extends React.Component { constructor() { super(); } render() { const arr = [ {"id":1,"name":"小明","age":12,"sex":"男"}, {"id":2,"name":"小紅","age":13,"sex":"女"}, {"id":3,"name":"小剛","age":14,"sex":"男"}, {"id":4,"name":"小白","age":15,"sex":"男"} ] return <div> <table> <tbody> { arr.map(item=>{ return <tr key={item.id}> <td>{item.id}</td> <td>{item.name}</td> <td>{item.age}</td> <td>{item.sex}</td> </tr> }) } </tbody> </table> </div> } }
3.8九九乘法表
學習的是二維數組的展開
我們先有一個套路,准備一個外層的數組,然后外層的循環中push內部數組:

import React from "react"; export default class App extends React.Component { //構造函數 constructor() { super(); } render() { var arr = []; for(var i = 1;i <= 9;i++){ var temp = [] for(var j = 1; j <= i; j++) { temp.push(<td key={j}> {i} * {j} = {i*j} </td>) } arr.push(<tr key={i}>{temp}</tr>) } return ( <div> <table> <tbody> {arr} </tbody> </table> </div> ) } };
3.9日歷
日歷的原理,決定一個日歷的畫風,有三要素:
這個月第一天是星期幾;
這個月有幾天;
上個月有幾天;
要知道2018年5月5日是星期幾: new Date(2018,5-1,5).getDay() 要知道2018年5月有幾天: new Date(2018,5,0).getDate()
本月有幾天,等價於下個月前一天是幾號,所以下個月的0號,就是本月的最后一天。
給日歷加農歷:
npm install --save solarlunar
import React from "react"; import solarLunar from 'solarLunar'; export default class App extends React.Component { //構造函數 constructor() { super(); } render() { var year = 2018; var month = 8; //是人類的月份,而不是計算機的 //本月第一天是星期幾 var TheMonthFirstDay = new Date(year,month - 1,1).getDay(); //本月共幾天 var TheMonthDays = new Date(year,month,0).getDate(); //上個月共幾天 var prevMonthDays = new Date(year,month-1,0).getDate(); var arr = []; //上個月的尾巴,本月第一天星期幾就有幾天上個月的尾巴 while (TheMonthFirstDay--){ arr.unshift(prevMonthDays--) } // 本月放進數組 var count = 1; while(TheMonthDays--){ arr.push(count++); } // 下個月的前有多少天,要補齊42天 var nextCount = 1; while ( arr.length != 42){ arr.push(nextCount++); } console.log(arr) //接下來要用這個一維數組集合JSX語法,展開為二維數組 const showTable = ()=>{ var domArr = []; for(var i = 0; i < arr.length / 7; i++){ domArr.push( <tr key={i}> { arr.slice(i * 7, i * 7 + 7).map(item=>{ var n = solarLunar.solar2lunar(year, month, item); return <td key={item}> {item} <br/> {n.term || n.dayCn} </td> }) } </tr> ) } return domArr; } return ( <div> <table> <thead> <tr> <th>日</th> <th>一</th> <th>二</th> <th>三</th> <th>四</th> <th>五</th> <th>六</th> </tr> </thead> <tbody> {showTable()} </tbody> </table> </div> ) } };