React開發環境安裝配置和基礎入門
React基礎入門
ReactDOM.render()
將指定的模板或節點內容插入指定的節點(通常是一個div)
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
以上表示,將一個h1標籤插入一個id為“example”的div節點內
<head>
<link rel="stylesheet" href="./src/css/style.css"/>
</head>
<div id="example" ></div>
<script src="./src/bundle.js"></script>
執行結果是
<head>
<link rel="stylesheet" href="./src/css/style.css"/>
</head>
<div id="example">hello, world</div>
<script src="./src/bundle.js"></script>
JSX
本質是語法糖,經過編譯後最終生成的是js程式碼
特點是支援類xml語法並且支援與js程式碼混寫
var names = ['Alice', 'Emily', 'Kate'];
ReactDOM.render(
<div>
{
names.map(function (name) {
return <div>Hello, {name}!</div>
})
}
</div>,
document.getElementById('example')
);
尖括號<>
內容屬於jsx語法內容;大括號{}
內容屬於js程式碼內容
如果jsx內包含一個js陣列物件變數,將自動呼叫其遍歷器獲取其全部成員
var arry = ["hello","world"];
<ul>
{arr.map(item => (
<li>{item+"zph"}</li>
))}
</ul>
另一個例子
class ShoppingList extends React.Component {
render() {
return (
<div className="shopping-list">
<h1>Shopping List for {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
);
}
}
//等同於
return React.createElement('div', {className: 'shopping-list'},
React.createElement('h1', /* ... h1 children ... */),
React.createElement('ul', /* ... ul children ... */)
);
// Example usage: <ShoppingList name="Mark" />
元件
元件本質是一個包含render方法的物件(類)。每次使用元件將生成一個新的物件例項
var MyComponent = React.createClass({
render: function() {
return <h1>Hello {this.props.name}</h1>;
}
});
ReactDOM.render(
<MyComponent name="John" />,
document.getElementById('example')
);
es6的module形式,向外暴露一個class類
export default class MyComponent extends React.Component{
constructor(){
super();
}
render(){
return(
<h1>Hello {this.props.name}</h1>;
);
}
}
js保留字問題:
class使用 className代替
for 使用htmlFor代替
this.props.children
- 如果當前元件沒有子節點 返回值是 undefined
- 如果只有一個子節點,返回值資料型別是 object
- 如果有多個子節點,返回值資料型別就是 array
var NotesList = React.createClass({
render: function() {
return (
<ol>
{
React.Children.map(this.props.children, function (child) {
return <li>{child}</li>;
})
}
</ol>
);
}
});
ReactDOM.render(
<NotesList>
<span>hello</span>
<span>world</span>
</NotesList>,
document.body
);
PropTypes型別檢查
React v15.5版本之後React.PropTypes使用方式已經移除,可使用 prop-types庫來代替
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
//本質是指定一個名為propTypes的靜態屬性,也可在類中使用static關鍵字的形式使用
一些基本型別的檢查
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// Anything that can be rendered: numbers, strings, elements or an array
// (or fragment) containing these types.
optionalNode: PropTypes.node,
// A React element.
optionalElement: PropTypes.element,
// You can also declare that a prop is an instance of a class. This uses
// JS's instanceof operator.
optionalMessage: PropTypes.instanceOf(Message),
// You can ensure that your prop is limited to specific values by treating
// it as an enum.
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// An object that could be one of many types
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
// An array of a certain type
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// An object with property values of a certain type
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
// An object taking on a particular shape
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// You can chain any of the above with `isRequired` to make sure a warning
// is shown if the prop isn't provided.
requiredFunc: PropTypes.func.isRequired,
// A value of any data type
requiredAny: PropTypes.any.isRequired,
以上是指定型別,如果需要指定是不可預設,可在後面追加isRequired,如
optionalArray: PropTypes.array.isRequeired
更詳細的可參考官方文件內容
defaultProps 設定預設值
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
// Specifies the default values for props:
Greeting.defaultProps = {
name: 'Stranger'
};
// Renders "Hello, Stranger":
ReactDOM.render(
<Greeting />,
document.getElementById('example')
);
Refs
直接獲取真實的DOM節點而非virtural DOM
使用場景:獲取焦點、觸發動畫、整合第三方DOM庫等
元件標籤內使用ref關鍵字定義一個callback回撥,此回撥將在元件載入或解除安裝完成後立即執行。回撥函式引數是dom節點,如
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// Explicitly focus the text input using the raw DOM API
this.textInput.focus();
}
render() {
// Use the `ref` callback to store a reference to the text input DOM
// element in an instance field (for example, this.textInput).
return (
<div>
<input
type="text"
ref={(input) => { this.textInput = input; }} />
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
方法元件中使用ref
function CustomTextInput(props) {
// textInput must be declared here so the ref callback can refer to it
let textInput = null;
function handleClick() {
textInput.focus();
}
return (
<div>
<input
type="text"
ref={(input) => { textInput = input; }} />
<input
type="button"
value="Focus the text input"
onClick={handleClick}
/>
</div>
);
}
避免使用String Refs 如,this.refs.textInput
此種使用方式以後將會被廢棄
this.state
- state被更新後將重新呼叫元件的render方法
- 作用域只針對當前的元件不會汙染其他元件
- 初始化state操作可放置於constructor建構函式中
- 呼叫
setState({key:value})
修改state
this.props
用於給獲取傳給當前元件的資料 如 <component key=value/>
給當前元件傳遞了key:value資料,當前元件可使用this.props.key
獲取value值
傳遞當前全部的props到子元件
<component {...this.props}/>
子元件更新父元件內容
通過給子元件傳函式
react-mixin
公用功能或程式碼
生命週期
React router
以下內容基於react-router 4.x版本
存在多個Repository:
* react-router
: React Router 提供核心的路由元件與函式
* react-router-dom
: 用於 DOM 繫結的 React Router
* react-router-native
: 用於 React Native 的 React Router
* react-router-redux
: React Router 和 Redux 的整合
* react-router-config
: 靜態路由配置幫助助手
web網站應用只需安裝react-router-dom
react-router-dom暴露出react-router中暴露的物件與方法,因此只需安裝並引用react-router-dom即可,react-router-dom比react-router多了
<Link>、 <BrowserRouter>
等
$ npm install --save react-router-dom
對於網頁專案,存在<BrowserRouter>
與<HashRouter>
兩種元件
區別:
?每個路由器都會建立一個history物件並用其保持追蹤當前location並且在有變化時對網站進行重新渲染
<Router/>
Router元件的children可以放任內容(元件或普通標籤),但只可有唯一的子元素
如,
<Router>
<div>
<ul>
<li><Link to="/">首頁</Link></li>
<li><Link to="/about">關於</Link></li>
<li><Link to="/topics">主題列表</Link></li>
</ul>
<hr/>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/topics" component={Topics}/>
</div>
</Router>
Router是所有路由元件共用的底層介面,一般我們的應用並不會使用這個介面,而是使用高階的路由:
<BrowserRouter>
:使用 HTML5 提供的 history API 來保持 UI 和 URL 的同步;<HashRouter
>:使用 URL 的 hash (例如:window.location.hash) 來保持 UI 和 URL 的同步;<MemoryRouter>
:能在記憶體儲存你 “URL” 的歷史紀錄(並沒有對位址列讀寫);<NativeRouter>
:為使用React Native提供路由支援;<StaticRouter>
:從不會改變地址;
<Route/>
當一個location匹配Route的path時,渲染某些UI內容
<Router>
<div>
<Route exact path="/" component={Home}/>
<Route path="/news" component={NewsFeed}/>
</div>
</Router>
Route的一些屬性:
* path(string): 路由匹配路徑。(沒有path屬性的Route 總是會 匹配);
* exact(bool):為true時,則要求路徑與location.pathname必須完全匹配;
* strict(bool):true的時候,有結尾斜線的路徑只能匹配有斜線的location.pathname
Route的三種不同的渲染內容的方式:
<Route component>
、<Route render>
、<Route render>
<Route component>
的優先順序要比<Route render>
高,所以不要在同一個中同時使用這兩個屬性。
<Link>
- to(string/object):要跳轉的路徑或地址;
- replace(bool):為 true 時,點選連結後將使用新地址替換掉訪問歷史記錄裡面的原地址;為 false 時,點選連結後將在原有訪問歷史記錄的基礎上新增一個新的紀錄。預設為 false;
// to為string
<Link to="/about">關於</Link>
// to為obj
<Link to={{
pathname: '/courses',
search: '?sort=name',
hash: '#the-hash',
state: { fromDashboard: true }
}}/>
// replace
<Link to="/courses" replace />
<NavLink>
<NavLink>
是<Link>
的一個特定版本, 會在匹配上當前 URL 的時候會給已經渲染的元素新增樣式引數,元件屬性:
- activeClassName(string):設定選中樣式,預設值為 active;
- activeStyle(object):當元素被選中時, 為此元素新增樣式;
- exact(bool):為 true 時, 只有當地址完全匹配 class 和 style 才會應用;
- strict(bool):為 true 時,在確定位置是否與當前 URL 匹配時,將考慮位置 pathname 後的斜線;
- isActive(func):判斷連結是否啟用的額外邏輯的功能;
// activeClassName選中時樣式為selected
<NavLink
to="/faq"
activeClassName="selected"
>FAQs</NavLink>
// 選中時樣式為activeStyle的樣式設定
<NavLink
to="/faq"
activeStyle={{
fontWeight: 'bold',
color: 'red'
}}
>FAQs</NavLink>
// 當event id為奇數的時候,啟用連結
const oddEvent = (match, location) => {
if (!match) {
return false
}
const eventID = parseInt(match.params.eventID)
return !isNaN(eventID) && eventID % 2 === 1
}
<NavLink
to="/events/123"
isActive={oddEvent}
>Event 123</NavLink>
<Switch/>
該元件用來渲染匹配地址的第一個
<Route>
或者<Redirect>
思考如下內容:
<Router>
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
</Router>
如果現在的URL是/about,那麼<About>
, <User>
,<NoMatch>
都會被渲染,因為它們都與路徑(path)匹配。這種設計,允許我們以多種方式將多個組合到我們的應用程式中,例如側欄(sidebars),麵包屑(breadcrumbs),bootstrap tabs等等。
然而,偶爾我們只想選擇一個來渲染。如果我們現在處於/about,我們也不希望匹配/:user(或者顯示我們的 “404” 頁面 )。此時需要 Switch 的方法來實現:
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>
</Switch>
現在,如果我們處於/about,<Switch>
將開始尋找匹配的<Route>
。<Route path="/about"/>
將被匹配, <Switch>
將停止尋找匹配並渲染<About>
。同樣,如果我們處於/michael,<User>
將被渲染。
react樣式使用
內聯樣式寫法
import React from 'react';
export default class ComponentHeader extends React.Component {
constructor(){
super();
this.state ={
miniHeader: false //預設載入的時候還是高(不是 mini)的頭部
};
};
switchHeader(){
this.setState({
miniHeader: !this.state.miniHeader
});
};
render() {
const styleComponentHeader = {
header: {
backgroundColor: "#333333",
color: "#FFFFFF",
"padding-top": (this.state.miniHeader) ? "3px" : "15px",
paddingBottom: (this.state.miniHeader) ? "3px" : "15px"
},
//還可以定義其他的樣式
};
return (
<header style={styleComponentHeader.header} className="smallFontSize"
onClick={this.switchHeader.bind(this)}>
<h1>這裡是頭部</h1>
</header>
)
}
}
引用樣式表形式
通過import css檔案的方式,元件可使用className引用樣式
css模組化
要解決的問題:
- 全域性汙染
- 命名混亂
需要安裝以下modules:
css-loader
style-loader
可選的
babel-plugin-react-attrs
用於解決className,htmlFor等名稱衝突問題
配置webpack.config
在webpack.config.js檔案loaders節點新增以下內容即可
下面是新增的 css 的 loader,也即是 css 模組化的配置
{
test: /\.css$/,
loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'
}
匯入css
var footerCss = require("../../footer.css")
使用css
<footer className = {footerCss.miniFooter}
/>
全域性樣式:在css檔案中定義中使用global顯式指定此樣式將作為全域性樣式使用。預設樣式是loacal無需顯式
:local(.myclass)(color:red)
:global(.btn)(color:green)
JSX樣式和css互轉
Ant Design
類比另一個UI框架:material-UI
Ant Design 官網
Antd使用方式:
下面是使用 ant-design 的webpack.config配置檔案需要修改的loaders節點內容
{ test: /\.css$/, loader: 'style-loader!css-loader' }
主頁引入樣式
import 'antd/dist/antd.css'
元件中引入需要的控制元件
import { Input } from 'antd';