react.js+jsx+route+redux+mockjs+axios 聯合學習全筆記 入門教程
引入react框架
1,直接在網頁引入
<!--react主程式-->
<script src="https://cdn.bootcss.com/react/15.4.2/react.min.js"></script>
<!--與dom相關的操作庫-->
<script src="https://cdn.bootcss.com/react/15.4.2/react-dom.min.js"></script>
<!--轉化es6與jsx語法支援-->
<script src="https://cdn.bootcss.com/babel-standalone/6.22.1/babel.min.js" ></script>
2,在webpack中引入
先安裝npm install –save react react-dom
import React from 'react'
import ReactDOM from 'react-dom'
渲染頁面
import React from 'react'
import ReactDOM from 'react-dom'
//react渲染方法
ReactDOM.render(
//jsx寫法的html元素
<h1>Hello, world!</h1>,
//渲染目標元素
document.getElementById('area' )
)
元素
建立一個網頁元素
//建立一個元素element
let element = <h1>Hello,element!</h1>
//element元素可以在render()直接中渲染
ReactDOM.render(
element,
document.getElementById('root')
);
//element元素可以在元件中呼叫
class Hello extends React.Component {
render(){
return (
<ul>
{listItems}
</ul>
);
}
}
元件
建立一個函式元件
function Hello(props) {
return <h1>Hello, {props.name}</h1>;
}
建立一個類元件
//建立元件需要建立一個類,類名必須首字母大寫,必須繼承React.Component並實現render()方法
class Hello extends React.Component {
render() {
return <h1>Hello, world!</h1>
//這裡可以直接返回元素element
//return element
}
}
渲染元件
//將元件類名按html形式寫在render方法中即可在頁面中看到
ReactDOM.render(<Hello />, document.getElementById('root'))
元件相互呼叫
//元件A
class HelloA extends React.Component {
render() {
return <h1>this is A</h1>
}
}
//元件B呼叫元件A
class HelloB extends React.Component {
render() {
return (
<div>
<h1>this is B</h1>
//此處呼叫元件A
<HelloA />
</div>
)
}
}
元素呼叫元件
const element = <HellA />;
元件傳值
父元件通過屬性的方式傳值給子元件
class HelloA extends React.Component {
render() {
return (
//此時元件HelloA 獲得attr的值
<HelloA attr='fuck'/>
)
}
}
子元件獲取值
class HelloA extends React.Component {
render() {
//得到父元件傳來的attr值
return <h1>this is A {this.props.attr}</h1>
}
}
值驗證
引入PropType庫,驗證值,避免錯誤。
import PropTypes from 'prop-types'
MyComponent.propTypes = {
// 你可以將屬性宣告為以下 JS 原生型別
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
}
//詳情:[https://doc.react-china.org/docs/typechecking-with-
在元件中使用
//新建元件類
class Test extends Component {
//驗證屬性'name'為字串,並且不為空
static propTypes = {
name: PropTypes.string.isRequired
}
//渲染
render() {
return (
<div className='aaa'>
<p className='tes'>{this.props.name}</p>
</div>
)
}
}
元件的狀態與生命週期
1,狀態state與生命週期只能應用於用類建立的元件上。不能應用與方法建立的元件上
2,狀態state的初始化需要用es6類的建構函式。
class NewComponent extends React.Component {
//constructor是es6類的構造方法。props父級呼叫該元件時傳遞的屬性資料
constructor(props) {
//super()方法是子類繼承父類必要條件
super(props);
//將date賦予state this.state只能在constructor初始化
this.state = {date: new Date()};
}
//自定義方法
change() {
//該方法用於更新state狀態,只有通過該方法,才會重新渲染
this.setState({
date: new Date()
});
}
//渲染
render() {
return (
<h1>Hello, world!{this.state.date}</h1>
);
}
//鉤子函式 當虛擬dom掛在到網頁dom上時立即執行
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
//鉤子函式 當前dom即將從網頁dom解除安裝時執行
componentWillUnmount() {
clearInterval(this.timerID);
}
}
事件
在react+jsx中 事件名用駝峰寫法。並且方法用中括號表示
避免被短時間內觸發太多次事件的方法控制呼叫
<!--html:-->
<button onclick='someFun()' />
<!--react+jsx:-->
<button onClick={someFun} />
事件方法預設無法被繫結到this上,以下幾種方法可以解決
1,在元件類的建構函式中繫結
//在建構函式中繫結
constructor(props) {
super(props)
this.clickFunc = this.clickFunc.bind(this)
console.dir(this)
}
//只有繫結才能獲取到this
clickFunc(){
console.dir(this)
}
2,在呼叫時使用回撥
<button onClick={(e) => this.clickFunc(e)}>
3,將事件方法使用箭頭函式寫法(需要屬性初始化器語法開啟)
clickFunc=(e)=>{
//事件可以通過e獲取引數
console.info(e.target.value)
console.dir(this)
}
事件傳值
//首先建立方法接受引數
handleClick(index, e) {
console.info(index)
// e.preventDefault()]
}
render() {
//使用箭頭函式傳值。如果使用普通寫法,函式會立即執行。
<button key={index} className='button' onClick={() => this.handleClick(index)}>
列表
元素方式
let list=[3, 1, 2, 44]
let ListItem=list.map(
//key是唯一標示,x是
(number, index) => <p key={index}>{number}</p>
)
jsx嵌入方式
<ul>
{list.map((number) =>
<ListItem key={number.toString()}
value={number} />
)}
</ul>
表單
所謂的受控元件,就是react實現表單的雙向繫結,只不過它實現的比較複雜。。。。。
class NameForm extends React.Component {
constructor(props) {
super(props);
//初始化狀態
this.state = {value: ''};
//繫結事件
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
//值變動事件
handleChange(event) {
this.setState({value: event.target.value});
}
//提交事件
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
//在此處繫結元件的值,並且輸入框的值發生改變時也會觸發事件方法改變值
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
元素組合
a元件呼叫b元件就是繼承
class A extends React.Component {
render(){
return <div><div>
}
}
class B extends React.Component {
render(){
return <B></B>
}
}
那麼如果這時元件B需要將元素嵌入到元件A中呢,這時就需要props.children 相當於(VUEJS中到繼承)
class A extends React.Component {
render(){
return <div>
//從外部內嵌到元素位置
{props.children}
<div>
}
}
class B extends React.Component {
render(){
return <A>
//在此處內嵌
<p> fuck u </p>
</A>
}
}
狀態提升
跨元件呼叫狀態時,父元件通過屬性傳遞到方式 將state與setSate傳遞給 子元件到props中。子元件發生變化立即更新props傳過來到state,達成了狀態提升與同步。
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
this.state = {temperature: '', scale: 'c'};
}
handleCelsiusChange(temperature) {
this.setState({scale: 'c', temperature});
}
handleFahrenheitChange(temperature) {
this.setState({scale: 'f', temperature});
}
render() {
const scale = this.state.scale;
const temperature = this.state.temperature;
const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
return (
<div>
<TemperatureInput
scale="c"
//子元件到值來自父元件傳遞
temperature={celsius}
//子元件發生變化更新父元件到 setState控制方法
onTemperatureChange={this.handleCelsiusChange} />
<TemperatureInput
scale="f"
temperature={fahrenheit}
onTemperatureChange={this.handleFahrenheitChange} />
<BoilingVerdict
celsius={parseFloat(celsius)} />
</div>
);
}
}
直接修改dom元素
vue中有相同到東西。但用著方便多類。在react中它只能對class宣告對物件使用。
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// 建立 ref 儲存 textInput DOM 元素
this.textInput = React.createRef();
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// 直接使用原生 API 使 text 輸入框獲得焦點
// 注意:通過 "current" 取得 DOM 節點
this.textInput.current.focus();
}
render() {
// 告訴 React 我們想把 <input> ref 關聯到構造器裡建立的 `textInput` 上
return (
<div>
<input
type="text"
ref={this.textInput}} />
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
Context跨元件傳值
當元件a包含元件b,元件b又包含元件c時,如果從a向c傳值,就要先傳到b,再從b傳到c。而使用context就可以直接一步從a傳到c
(不要僅僅為了避免在幾個層級下的元件傳遞 props 而使用 context,它是被用於在多個層級的多個元件需要訪問相同資料的情景。)
// 建立一個 theme Context, 預設 theme 的值為 light
const ThemeContext = React.createContext('light');
function ThemedButton(props) {
// ThemedButton 元件從 context 接收 theme
return (
<ThemeContext.Consumer>
{theme => <Button {...props} theme={theme} />}
</ThemeContext.Consumer>
);
}
// 中間元件
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
class App extends React.Component {
render() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}
不被渲染到包裹標籤Fragments
有些時候你要返回一個多元素集合,但react只允許你返回一個包含子標籤的單個元素,有時我們並不希望這個外部包裹元素被渲染出來,這時可以使用空標籤
class Columns extends React.Component {
render() {
return (
<>
<td>Hello</td>
<td>World</td>
</>
);
}
}
需要key的時候使用React.Fragment
class Columns extends React.Component {
render() {
return (
<React.Fragment>
<td>Hello</td>
<td>World</td>
</React.Fragment>
);
}
}
將元素插入到現有dom節點的方法Portals
render() {
//將this.props.children渲染到制定到domNode上
return ReactDOM.createPortal(
this.props.child歐ren,
domNode,
);
}
路由
//安裝路由
npm install --save react-router-dom
//引入模組
import {
//Router就是個容器。觸發route功能都需要在Route標籤中。而且只能有一個子標籤。
//模仿正常都地址
BrowserRouter,
//地址中有#符號
HashRouter,
//受link控制的 裝載元件的容器
Route,
//普通的跳轉工具
Link,
//API比較多的跳轉工具
NavLink
} from 'react-router-dom'
兩個元件
class About extends React.Component {
render() {
return (
<div> about </div>
)
}
}
class Contact extends React.Component {
render() {
return (
<div> contack </div>
)
}
}
主元件
export default class IndexPage extends Component {
render() {
return (
//路由容器,basname設定基礎path
<BrowserRouter basename='/home'>
//只能有一個子
<div>
//元件容器。path設定匹配地址,component設定匹配元件。
<Route path='/about' component={About} />
<Route path='/contact' component={Contact} />
//連結按鈕。相當於a標籤
<Link to='about'>about</Link>
<Link to='contact'>contact</Link>
</div>
</BrowserRouter>
)
}
}
發起資料請求(ajax訪問伺服器)
使用ajax庫
可以使用自己喜歡的 AJAX 庫,如jQuery AJAX 和瀏覽器內建的 window.fetch。 值得一提的是Axios,目前被vue官方宣傳使用,傻瓜操作,完美的跨域解決方案,值得擁有。
在何處使用
資料請求應該在componentDidMount 生命週期方法內傳送。這樣你才能夠在請求的資料到達時使用 setState 更新你的元件。應該在componentWillUnmount生命週期內取消請求
1.使用window.fetch方法
fetch('sdf.json地址', {
// 是否允許跨域帶cockie
credentials: 'include',
//請求頭
headers: {
'Accept': 'application/json'
},
//方法
method: 'get'
}).then(res => res).then(
//獲取結果
(result) => {
this.setState({
list: result.list.id
})
},
//捕獲錯誤
(error) => {
this.setState({
error
})
}
)
2.使用jquery ajax
$.ajax({
url:'http://www.bai.com',
type:"DELETE",
data:{
id:1//假設需要刪除id=1的資料
},
dataType:'json',
success:function(e){
console.log(e)
}
})
3.重點推薦axios
//假資料,可以攔截請求,用於前端測試,後面有介紹
Mock.mock(
/\.json/,
'get',
// 屬性 list 的值是一個數組,其中含有 1 到 10 個元素
{
'age|20-30':25
}
)
//發起請求
Axios({
//方法,restfull
method: 'get',
//地址
url: 'asdf.json',
//返回格式
responseType: 'json'
}).then(function(response) {
//結果
console.dir(response.data)
})
資料mockjs
示例的 API 返回的 JSON 物件使用mock生成,mock可以攔截ajax請求,返回加資料,便於前端除錯。
安裝mockjs
npm i mockjs
配置
var Mock = require('mockjs')
var data = Mock.mock(
//期望被攔截的地址。當你的react請求這個地址時就會返回我們的加資料
/\.json/,
'get',
// 屬性 list 的值是一個數組,其中含有 1 到 10 個元素
{
'age|20-30':25
}
)
// 輸出結果
console.log(JSON.stringify(data, null, 4))
隨機資料
const Random = Mock.Random
console.dir(Random.csentence(5, 30))
/*模擬刪除資料的方式*/
var arr=[
{name:'fei',age:20,id:1},
{name:'liang',age:30,id:2},
{name:'jun',age:40,id:3},
{name:'ming',age:50,id:4}
]
Mock.mock('http://www.bai.com','delete',function(options){
var id = parseInt(options.body.split("=")[1])//獲取刪除的id
var index;
for(var i in arr){
if(arr[i].id===id){//在陣列arr裡找到這個id
index=i
break;
}
}
arr.splice(index,1)//把這個id對應的物件從數組裡刪除
return arr;//返回這個陣列,也就是返回處理後的假資料
})
less的坑
如果less中 不能使用函式,那可能是style-css 和 less-loader順序問題。
在less檔案中無法使用css3的@keyfreames動畫語法。這時可以在檔案中定義一個類的keyfreames語句,然後在頁面中使用improt style from 'xxx.less' 並在模版中使用<div style={style.keyfreamClassName }\/>用這種齷齪的方法呼叫style
SEO問題
由於資料內容都是前端渲染出來的,所以不利於搜尋引擎seo。這時需要server render來處理就好了。