初識React:仿網易公開課(react+antd)

Gaofeng發表於2018-08-05

初識React:仿網易公開課(react+antd)

前言


最近開始學習React,於是便仿了一下網易公開課,來加強自己對React的理解,在這裡和大家分享一下我 這幾天coding的React專案和自己踩的一些坑

使用到的技術棧

  • 資料請求:axios
  • 後臺搭建:koa
  • 跨域解決:koa-cors
  • css預編譯器:stylus
  • UI框架:antd
  • 其他元件:rewire swiper better-scroll

專案下載步驟

  • git clone https://github.com/fsafafaf/react-wyclass.git
  • 安裝
    # 安裝依賴
    npm install
    # 啟動後端
    yarn server
    # 啟動前端
    yarn start
複製程式碼

效果圖

登入

初識React:仿網易公開課(react+antd)

訂閱功能
初識React:仿網易公開課(react+antd)

搜尋功能
初識React:仿網易公開課(react+antd)

總覽

初識React:仿網易公開課(react+antd)

功能實現

  • tabbar切換
  • 輪播圖和滑動功能
  • 搜尋功能:根據使用者輸入查詢所有課程中符合要求的課程並顯示
  • 登入功能:根據使用者的登入狀態來判斷是否可以訂閱
  • 訂閱功能:根據使用者訂閱的賬號顯示訂閱內容
  • 播放功能:通過router傳參確定視訊內容

踩過的坑

一:react-router-dom

① JS切換路由

在這個專案中,我使用了react-redux來管理資料的狀態,但是並沒有連線資料庫,所以介面一重新整理,store裡面的state就全部清零了。這導致我一開始用location跳轉就一直儲存不了資料,糾結了半天,於是就百度了一下,最後發現可以使用 react-router-dom 的Redirect功能實現頁面的跳轉
實現程式碼

import { Redirect } from 'react-router-dom'

handleOnclick = () => {
    this.setState({ redirect: true })
}
render () {
    if(this.state.redirect){
            return <Redirect push to="/home" />;
    }
    return (<button onClcik={this.handleOnClick} type="button">Button</button>;)
}
複製程式碼

②跳轉至子路由的資料傳入

在coding播放頁面的時候,我一開始是用redux來管理傳入播放頁面的資料,但是頁面重新整理過後,redux傳來的ID也就消失了,頁面便成了一片白。emmmm...我沉思了一番,突然發現頁面的路由並沒有改變,還是以ID結尾的路由!那我為什麼不利用路由來匹配播放介面應該傳入的資料呢!思考完就動手,這裡得提一下我在父元件裡面進入播放頁面的方法:利用 this.props.match來獲得當前頁面的路由,然後再加上視訊的ID,將其做為子頁面的路由

實現程式碼

import { Route } from 'react-router-dom'
class home extends Component {
    selectVideo(video, url) {
        return () => {
            this.props.history.push({
                pathname: url
            })
        }
    }
    return (
    
        <a onClick={this.selectVideo(item,`${match.url + '/' + item.id}`)}>
            <img src={item.img} />
            <div className="home-text">{item.text}</div>
        </a>
        
        <Route path = {`${match.url + '/:id'}`} component = {Play}/>
    )
}
複製程式碼

然後只需要在子頁面中將id篩選出來,再將id匹配一下就能獲得要播放的資料了

實現程式碼

class Play extends Component {
    constructor(props) {
        super(props);
        const arr = this.props.history.location.pathname.split('/')
        const id = parseInt(arr[arr.length-1])
        this.state = {
            id: id
        }
    }
}
複製程式碼

二:react元件的生命週期

react元件的生命週期有3種狀態

  • Mounting:已插入真實 DOM
  • Updating:正在被重新渲染
  • Unmounting:已移出真實 DOM

一般我們請求資料都是用componentDidMounting方法,但是這個方法不是萬能的,有的時候它並不靠譜。 在實現訂閱頁面時,我一開始用的就是在componentDidMounting方法中執行檢測訂閱賬號函式,這導致只有我在其他的頁面對賬號進行訂閱,訂閱頁面才會能重新渲染訂閱內容,而直接在訂閱頁面對賬號的訂閱進行操作,訂閱頁面就不會重新渲染。簡而言之就是componentDidMounting方法只會在重新載入元件的時候才會執行,而我們需要的是this.props每發生一次改變,都要重新渲染一遍訂閱內容,這種時候,我們就需要用到componentWillReceiveProps方法,它會在元件接收到一個新的 prop (更新後)時被呼叫,而且這個方法在初始化render時不會被呼叫。

實現程式碼

    componentWillReceiveProps() {
        getData().then(res => {
            const names = this.props.videos
            const arr = []
            if (names.length === 0) {
                this.setState({show: false})
            } else {
                this.setState({show: true})
            }
            for (var key in names) {
                for (var index in res) {
                    if (res[index].up === names[key])
                        arr.push(res[index])
                }
            }
            this.setState({
                videos: arr,
            })
        })
    }
複製程式碼

三:搜尋功能實現

因為該專案筆者用的是Antd框架搭建的初體驗,看到啥元件都想用一用。於是...當正在做搜尋功能的我看到了AutoComplete自動完成元件...我就...我就用了。現在回想起來,我真想回去扇自己一巴掌,根本用不來啊,白白浪費了1個小時。如果你想看AutoComplete怎麼實現搜尋功能,emmm...好吧,你也浪費了1分鐘,筆者根本沒實現?。下面就講一下筆者是怎麼實現的搜尋功能吧。
antd裡的Search元件的onSearch屬性會自動給我們返回一個value值,不用我們手動去獲取輸入框使用者輸入的值,所以 我們將value傳到我們自己定義的onSearch()函式中,然後對課程名集合allclass進行篩選,這裡判斷value值是否存在於課程名中我們用indexOf() >= 0 來判斷即可,如果不存在,indexOf()的結果就是-1。

實現程式碼

onSearch(value) {
        const result = this.state.allclass.filter(item => {
            if (item.Course.indexOf(value) >= 0)
                return item
        })
        console.log(result)
        this.setState({
            result: result
        })
    }
複製程式碼

篩選出來的資料,用map遍歷一下,就可以顯示出來了

render () {
    const result = this.state.result.map(item => {
            return  (  
                <div key={item.id} >
                    <NavLink to={`/home/${item.id}`}>
                        <div className="search-bar">
                            <div className="search-text">{item.Course}</div>
                            <Icon type="right" style={{ color: '#9b9b9b' }} />
                        </div>
                    </NavLink>
                </div>
            )
        })
    return (
    <div className="class-search">
        <div className="search">
            <Search
                placeholder="9種"
                onSearch={value => this.onSearch(value)}
                style={{ width: 300 }}
                autoFocus
            />
            <div className="cancel-button" onClick={this.searchOut()}>取消</div>
        </div>

        <div className="content">
            {result}
        </div>
    </div>
    )
}
複製程式碼

結語

這個react專案是我邊學習邊coding的,還有一些小bug沒解決,比如退出登入的時候 my介面並不會自動渲染,必須要重新切換路由,未登入狀態才能渲染到頁面上,不過學習不就是這樣嗎,不斷的學習,不斷的踩坑,不斷的進步!希望我這篇文章能對你有所幫助。最後附上我的專案地址,如果你覺得不錯,可以給我個star哦!

相關文章