1. 程式人生 > >react.js+jsx+route+redux+mockjs+axios 聯合學習全筆記 入門教程

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來處理就好了。