1 創建React-APP
為了加速npm下載速度,先把npm設置為淘寶鏡像地址。
npm config set registry http://registry.npm.taobao.org/
復制代碼也可以使用cnpm,根據喜好自行選擇。
通過官方的create-react-app,找個喜歡的目錄,執行:
npx create-react-app react-app
復制代碼命令最后的react-app是項目的名稱,可以自行更改。
稍等片刻即可完成安裝。安裝完成后,可以使用npm或者yarn啟動項目。
進入項目目錄,並啟動項目:
cd react-app
yarn start (或者使用npm start)
復制代碼如果沒有安裝yarn,可以前往yarn中文網站安裝:
yarn.bootcss.com/
啟動后,可以通過以下地址訪問項目:
2 精簡項目
2.1 刪除文件
接下來,刪除一般項目中用不到的文件,最簡化項目。
├─ /node_modules
├─ package.json
├─ /public
| ├─ favicon.ico
| ├─ index.html
- | ├─ logo192.png
- | ├─ logo512.png
- | ├─ mainfest.json
- | └─ robots.txt
├─ README.md
├─ /src - | ├─ App.css
| ├─ App.js - | ├─ App.test.js (jTest自動化測試)
- | ├─ index.css
- | ├─ index.js
- | ├─ logo.svg
- | ├─ serviceWorker.js
- | └─ setuoTests.js (PWA)
└─ yarn.lock
復制代碼以上文件刪除后,頁面會報錯。這是因為相應的文件引用已不存在。需要繼續修改代碼。
2.2 簡化代碼
現在目錄結構如下,清爽許多:
├─ /node_modules
├─ package.json
├─ /public
| ├─ favicon.ico
| └─ index.html
├─ README.md
├─ /src
| ├─ App.js
| └─ index.js
└─ yarn.lock
復制代碼逐個修改以下文件:
src/App.js代碼簡化如下:
import React from 'react'
function App() {
return (
This is React App.
)
}
export default App
復制代碼src/index.js代碼簡化如下:
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(
復制代碼public/index.html
2.3 使用Fragment去掉組件外層標簽
react要求每個組件HTML的最外層必須是由一個標簽包裹,且不能存在並列的標簽。例如,在src/App.js中,如果是這樣就會報錯:
// 以下代碼將會報錯,最外層不能存在並列的標簽。
function App() {
return (
This is React App.
This is React App-other.
)
}
復制代碼如果確實需要這樣的HTML,並且不想再添加一個父級標簽,可以使用Fragment作為最外層。代碼修改如下:
M import React, { Fragment } from 'react'
function App() {
return (
-
<Fragment> <div className="App"> <h1>This is React App.</h1> </div> <div className="App-other"> <h1>This is React App-ohter.</h1> </div> -
</Fragment> )}
export default App
復制代碼
以上僅為了說明Fragment的使用效果。在某些組件嵌套的使用場景下,非常適合使用Fragment。例如父組件是,而子組件可以用包裹多個 。
3 項目目錄結構
項目目錄結構可根據項目實際靈活制定。這里分享下我常用的結構,僅供參考。
├─ /node_modules
├─ package.json
├─ /public
| ├─ favicon.ico <-- 網頁圖標
| └─ index.html <-- HTML頁模板
├─ README.md
├─ /src
| ├─ /common <-- 全局公用目錄
| | ├─ /fonts <-- 字體文件目錄
| | ├─ /images <-- 圖片文件目錄
| | ├─ /js <-- 公用js文件目錄
| | └─ /style <-- 公用樣式文件目錄
| | | ├─ frame.css <-- 全部公用樣式(import其他css)
| | | ├─ reset.css <-- 清零樣式
| | | └─ global.css <-- 全局公用樣式
| ├─ /components <-- 公共模塊組件目錄
| | ├─ /header <-- 頭部導航模塊
| | | ├─ index.js <-- header主文件
| | | └─ header.css <-- header樣式文件
| | └─ ... <-- 其他模塊
| ├─ /pages <-- 頁面組件目錄
| | ├─ /home <-- home頁目錄
| | | ├─ index.js <-- home主文件
| | | └─ home.css <-- home樣式文件
| | ├─ /login <-- login頁目錄
| | | ├─ index.js <-- login主文件
| | | └─ login.css <-- login樣式文件
| | └─ ... <-- 其他頁面
| ├─ App.js <-- 項目主模塊
| └─ index.js <-- 項目入口文件
└─ yarn.lock
復制代碼3.1 引入全局公用樣式
在frame.css里引入其他公用樣式:
src/common/style/frame.css
@import './reset.css';
@import './global.css';
復制代碼然后在src/index.js里引入frame.css
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App' -
import './common/style/frame.css'
ReactDOM.render(
, document.getElementById('root'))
復制代碼如圖,頁面全局樣式已生效。
3.2 支持Sass/Less/Stylus
工欲善其事必先利其器,這么高大上的react怎能好意思用最原始的css搭配呢?create-react-app默認情況下未暴露配置文件。要更靈活配置項目,需要將配置文件暴露出來。
執行以下命令,暴露配置文件:
※注意:暴露配置的文件的操作不可逆!
npm run eject
復制代碼如果之前沒有提及git的話,可能會報以下錯誤:
Remove untracked files, stash or commit any changes, and try again
復制代碼需要先在項目根目錄下執行:
git add .
git commit -m "初始化項目(備注)"
復制代碼稍等片刻,eject成功,目錄變化如下:
-
├─ /config
-
| ├─ /jest
-
| ├─ env.js
-
| ├─ module.js
-
| ├─ paths.js
-
| ├─ pnpTs.js
-
| ├─ webpack.config.js <-- webpack配置文件
-
| └─ webpackDevServer.config.js
├─ /node_modules
├─ package.json
├─ /public
| ├─ favicon.ico
| └─ index.html
├─ README.md -
├─ /scripts
-
| ├─ build.js
-
| ├─ start.js
-
| └─ test.js
├─ /src
| ├─ /common <-- 全局公用目錄
| ├─ /components <-- 公共模塊組件目錄
| ├─ /pages <-- 頁面組件目錄
| ├─ App.js <-- 項目主模塊
| └─ index.js <-- 項目入口文件
└─ yarn.lock
復制代碼3.2.1 支持Sass/Scss
eject后,雖然package.json以及webpack.config.js里有了sass相關代碼,但是要正確使用Sass/Scss,還要再安裝node-sass。
執行以下命令:
npm install node-sass --save-dev
復制代碼安裝完成后,項目已支持Sass/Scss,可以將原css文件后綴名修改為sacc/scss,別忘了把src/index.js中引入的frame.css后綴名修改為sacc/scss。
3.2.2 支持Less
支持Less稍微多一點步驟,首先安裝less和less-loader:
npm install less less-loader --save-dev
復制代碼然后修改config/webpack.config.js:
// style files regexes
const cssRegex = /.css$/;
const cssModuleRegex = /.module.css$/;
const sassRegex = /.(scss|sass)$/;
const sassModuleRegex = /.module.(scss|sass)$/; -
const lessRegex = /.less$/;
-
const lessModuleRegex = /.module.less$/;
...(略)
// Opt-in support for SASS (using .scss or .sass extensions).
// By default we support SASS Modules with the
// extensions .module.scss or .module.sass
{
test: sassRegex,
exclude: sassModuleRegex,
use: getStyleLoaders(
{
importLoaders: 2,
sourceMap: isEnvProduction && shouldUseSourceMap,
},
'sass-loader'
),
// Don't consider CSS imports dead code even if the
// containing package claims to have no side effects.
// Remove this when webpack adds a warning or an error for this.
// See https://github.com/webpack/webpack/issues/6571
sideEffects: true,
},
// Adds support for CSS Modules, but using SASS
// using the extension .module.scss or .module.sass
{
test: sassModuleRegex,
use: getStyleLoaders(
{
importLoaders: 2,
sourceMap: isEnvProduction && shouldUseSourceMap,
modules: {
getLocalIdent: getCSSModuleLocalIdent,
},
},
'sass-loader'
),
},
// 以下這里仿照上面sass的代碼,配置下less。 -
{
-
test: lessRegex, -
exclude: lessModuleRegex, -
use: getStyleLoaders( -
{ -
importLoaders: 2, -
sourceMap: isEnvProduction && shouldUseSourceMap, -
}, -
'less-loader' -
), -
sideEffects: true, -
},
-
{
-
test: lessModuleRegex, -
use: getStyleLoaders( -
{ -
importLoaders: 2, -
sourceMap: isEnvProduction && shouldUseSourceMap, -
modules: { -
getLocalIdent: getCSSModuleLocalIdent, -
}, -
}, -
'less-loader' -
), -
},
復制代碼修改后需要執行yarn start重啟項目。
然后將原css文件的后綴名修改為less,src/index.js中引入的frame.less,頁面已正常解析less。
3.2.3 支持Stylus
支持Stylus跟Less完全一樣,首先安裝stylus和stylus-loader:
執行以下命令:
npm install stylus stylus-loader --save-dev
復制代碼安裝完成后,按照上一小節介紹的支持less的方法,修改config/webpack.config.js。完成后重啟項目,引入stylus文件可以正常解析了。
我個人習慣使用Stylus,因此后續的講解中使用Stylus。同時,把src/common/下的style目錄也更名為stylus。
├─ /config
├─ /node_modules
├─ package.json
├─ /public
├─ README.md
├─ /scripts
├─ /src
| ├─ /common <-- 全局公用目錄
| | ├─ /fonts
| | ├─ /images
| | ├─ /js
M | | └─ /stylus
M | | | ├─ frame.styl
M | | | ├─ reset.styl
M | | | └─ global.styl
| ├─ /components <-- 公共模塊組件目錄
| ├─ /pages <-- 頁面組件目錄
| ├─ App.js <-- 項目主模塊
| └─ index.js <-- 項目入口文件
└─ yarn.lock
復制代碼frame.styl代碼如下:
@import './reset.styl';
@import './global.styl';
復制代碼src/index.js代碼修改如下:
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
M import './common/style/frame.styl'ReactDOM.render(
, document.getElementById('root'))
復制代碼最基本的配置搞定了,接下來要開始引入頁面(pages)了。頁面的切換需要使用路由(Router),請繼續閱讀下面的章節。
4 路由
4.1 頁面構建
首先,構建home和login頁面。
src/pages/home/index.js代碼:
import React, { Component } from 'react'
import './home.styl'
class Home extends Component {
render() {
return (
Home page
)
}
}
export default Home
復制代碼src/pages/home/home.styl代碼
.P-home
h1
padding: 20px 0
font-size: 30px
color: #fff
background: #67C23A
text-align: center
復制代碼src/pages/login/index.js代碼:
import React, { Component } from 'react'
import './login.styl'
class Login extends Component {
render() {
return (
Login page
)
}
}
export default Login
復制代碼src/pages/login/login.styl代碼
.P-login
h1
background: #E6A23C
復制代碼我個人的習慣是,僅供參考:
全局公用級別(不需要模塊化)的className,用G-xxx。例如G-autocut(截字)、G-color-red(文字紅色)。
頁面級別的className,用P-xxx。
模塊級別的className,用M-xxx。
接下來,我們使用react-router-dom實現路由。
4.2 使用react-router-dom
執行安裝命令:
npm install react-router-dom --save
復制代碼修改src/App.js,代碼如下:
import React, { Fragment } from 'react'
import Login from './pages/login'
import Home from './pages/home'
import { HashRouter, Route, Switch, Redirect } from 'react-router-dom'
function App() {
return (
<Redirect to={"/home"} />
)
}
export default App
復制代碼App.js引入了Home和Login兩個頁面級組件。然后使用react-router-dom分別設置了路徑。
import的機制是默認尋找index.js,所以每個組件的主文件名設為index.js,在引用的時候就可以省略文件名。
這里說明一下
path表示路徑,這個很好理解。
component表示綁定的組件。
exact表示是否精確匹配。
如果沒有設置exact,那么:
localhost:3000/會顯示Home頁,
localhost:3000/abc也會顯示Home頁。
因為匹配到了前面的"/",路由就會成功。
最后的
來看下效果:
訪問http://localhost:3000/#/login效果:
訪問http://localhost:3000/#/home效果:
4.3 路由跳轉
接下來,簡單介紹下如果在頁面之間進行路由跳轉。
在Login頁面添加一個用於跳轉至Home頁的按鈕,代碼修改如下:
import React, { Component } from 'react'
import './login.styl'
class Login extends Component {
render() {
return (
<div className="P-login">
<h1>Login page</h1>
-
<button onClick={this.gotoHome.bind(this)}>跳轉Home頁</button> </div> ) } -
gotoHome() { -
this.props.history.push('/home') -
}}
export default Login
復制代碼注意button的onClick里要bind(this),否則,在gotoHome里的this是undefined。
當然,也可以這么寫:
<button onClick={() => {this.gotoHome()}}>跳轉Home頁
復制代碼最終目的都是要讓gotoHome中的this指向正確的作用域。
5 組件引入
這章節內容也很容易,接觸過vue的同學應該也很清楚,為了教程的完整性,還是簡單說一下。下面來簡單實現一個公用的頭部組件。
5.1 創建header組件
目錄結構如下:
| ├─ /components <-- 公共模塊組件目錄
- | | ├─ /header <-- 公用header組件
- | | | ├─ index.js
- | | | └─ header.styl
復制代碼src/components/header/index.js代碼:
import React, { Component } from 'react'
import './header.styl'
class Header extends Component {
render() {
return (
Header
)
}
}
export default Header
復制代碼src/components/header/header.styl代碼:
.M-header
height: 40px
line-height: 40px
font-size: 36px
color: #fff
background: #409EFF
復制代碼5.2 引入Header組件
然后,在Home和Login頁面里引入Header組件。
以Home頁面為例,修改src/pages/home/index.js:
import React, { Component } from 'react'
-
import Header from '../../components/header'
import './home.styl'class Home extends Component {
render() {
return (
-
<Header /> <h1>Home page</h1> </div> ) }}
export default Home
復制代碼同樣的方式在Login頁面也引入Header組件,代碼就不放出了。效果如下:
5.3 組件傳參
使用過vue的同學都知道,vue組件有data和props。對應react的是state和props。
react向子組件傳參使用以下方式:
安裝完成后,打開chrome調試工具,可以清晰的看到react項目代碼結構。
