React構建我的博客

前言

在學習react的過程當中,深深的被react的函數式編程的模式所吸引,一切皆組件,全部的東西都是JavaScript。React框架其實功能很單一,主要負責渲染的功能,可是社區很活躍,衍生出了不少優秀的庫和工具。我的以爲,想要作好一個項目,每每須要其餘庫和工具的配合,例如redux管理數據,react-router管理路由等,掌握基本的webpack配置es6語法,而後想要提升性能,還有配合react的鉤子函數和immutable.js,何時組件不須要從新渲染,next.js服務端渲染等等...
一直有一個想法就是重構本身的博客,恰好這段時間放假,又恰好學習了react,因而就有了這個項目。javascript

項目地址https://github.com/k-water/re...
若是以爲不錯的話,您能夠點右上角 "Star" 支持一下 謝謝! ^_^

技術棧

前端html

  • react
  • react-redux
  • react-thunk
  • react-router
  • axios
  • eslint
  • maked
  • highlight.js
  • antd
  • es6/7/8

後臺前端

  • spring boot

此項目採用先後端分離的實現,後臺接口基於RESTful規範設計,只提供數據,前端負責路由跳轉,權限限制,渲染數據等。PS:因爲我是個前端er,因此這裏主要講的是前端。java

實現的功能

  • [x] admin增刪查改博客
  • [x] 博客標籤
  • [x] 博客內容markdown
  • [x] 博客內容頁展現目錄
  • [x] 返回頂部
  • [x] markdown代碼高亮
  • [x] 用戶登陸註冊
  • [x] 用戶評論
  • [x] 響應式

TODO

  • [ ] 博客分類
  • [ ] 點擊標籤搜索相關博客
  • [ ] 優化首頁側邊欄
  • [ ] 完善歸檔

效果預覽

首頁

內容頁

用戶登陸

用戶評論

後臺管理

我的總結

markdown渲染

在前端渲染markdown的時候遇到了一點問題,相關的包不少,可是各類包解析的結果都有差別,react周邊社區推薦的是 react-markdown,使用方法也很簡單react

import ReactMarkdown from 'react-markdown'

const input = '# This is a header\n\nAnd this is a paragraph'
ReactDOM.render(
    <ReactMarkdown source={input} />,
    document.getElementById('container')
)

可是發現react-markdown對錶格的支持不太友好,最後採用了marked,結合highlight.js對代碼部分實現高亮webpack

import marked from 'marked'
import hljs from 'highlight.js'
  componentWillMount() {
    marked.setOptions({
      highlight: code => hljs.highlightAuto(code).value
    })
  }

最後解析出來的是一個字符串,還須要將它插入dom中,因爲安全問題,React不提倡將字符串直接插入dom中,但React保留了一個API,能夠這樣作:ios

<div className="article-detail" 
  dangerouslySetInnerHTML={{ __html: marked(output)) }} />

React組件化

react的組件由dom視圖和state組成,state是數據中心,它的狀態決定着視圖的狀態。react只負責UI的渲染,與其餘框架監聽數據動態改變dom不一樣,react採用setState來控制視圖的更新。setState會自動調用render函數,觸發視圖的從新渲染,若是僅僅只是state數據的變化而沒有調用setState,並不會觸發更新。說到組件,就必須瞭解react組件的生命週期,官方的圖解以下:git

關於這部分的解釋網上有不少,能夠自行查閱。而我在開發過程用的最多的就是es6

  • componentWillMount()
  • componentDidMount()
  • shouldComponentUpdate(nextProps, nextState)

這幾個鉤子函數了,關於性能優化,能夠在shouldComponentUpdate上做文章,因爲shouldComponentUpdate默認返回true,簡單的方法能夠經過比較更新先後的數據結構是否相同來判斷組件是否須要從新渲染,這時候就能夠採用immutable.js了。github

組件之間通訊

react是單向數據流,自上而下的傳遞數據。解決複雜組件之間通訊的方法有不少。通常父子組件通訊是最簡單的,父組件將一個回調函數傳遞給子組件,子組件經過this.props直接調用該函數與父組件通訊。

若是組件之間嵌套很深,可使用上下文getChildContext來傳遞信息,這樣在不須要將函數一層層往下傳,任何一層的子級均可以經過this.context直接訪問,react-redux內部實現就是利用此方法。

兄弟組件之間沒法直接通訊,它們須要利用同一層的上級做爲中轉站。

Redux

redux不是必須的,若是不是複雜的組件通訊,邏輯簡單,用context就行。redux並非react特有的,其餘框架也可使用redux。當初爲了學習redux花費了很多時間,一開始並不理解redux中間的操做,看了不少前輩們寫的文章才逐漸明白。簡單說說redux。
redux由三部分組成:store, reducer, action

store是一個對象,它主要由三個方法:
dispatch
用於action的分發,當action傳入dispatch會當即執行,有些時候咱們不想它馬上觸發,能夠在createStore中使用middleware中間件對dispatch進行改造,例如redux-thunk,不過這是react-radux作的事了。
subscribe
顧名思義,監聽器,監聽state的變化,這個函數在store調用dispatch時會註冊一個listener監聽state變化。
getState
獲取store中的state,當咱們用action觸發reducer改變了state時,須要拿到新的state裏面的數據。getState在兩個地方會用到,一是經過dispatch提交action後store須要拿到state裏面的數據,二是利用subscribe監聽到state發生變化後調用它來獲取新的state數據。

說了這麼多,store的核心代碼其實很短:

/**
 * 應用觀察者模式
 * @param {Object} state
 * @param {Function} reducer
 */
function createStore(reducer) {
  let state = null
  const listeners = []
  const subscribe = listener => listeners.push(listener)
  const getState = () => state
  const dispatch = action => {
    // 覆蓋原對象
    state = reducer(state, action)
    listeners.forEach(listener => listener())
  }
  // 初始化state
  dispatch({})
  return {
    getState,
    dispatch,
    subscribe
  }
}

另外一部分,reducer是一個純函數(pure function),它接收一個state和action做爲參數,根據action的type返回一個新的state,若是傳入的action type沒有匹配到,則返回默認的state,簡單實現以下:

function reducer(state, action) {
  if (!state) {
    return {
      title: {
        text: "water make redux",
        color: "red"
      },
      content: {
        text: "water make redux",
        color: "green"
      }
    }
  }
  switch (action.type) {
    case "UPDATE_TITLE_TEXT":
      return {
        ...state,
        title: {
          ...state.title,
          text: action.text
        }
      }
    case "UPDATE_TITLE_COLOR":
      return {
        ...state,
        title: {
          ...state.title,
          color: action.color
        }
      }
    default:
      return state
  }
}

action比較簡單,它返回一個對象,其中type屬性是必須的,同時也能夠傳入一些其餘的數據。
使用例子以下:

/ 生成store
const store = createStore(reducer)
let oldState = store.getState()
// 監聽數據變化從新渲頁面
store.subscribe(() => {
  const newState = store.getState()
  renderApp(newState, oldState)
  oldState = newState
})
// 首次渲染頁面
renderApp(store.getState())
store.dispatch({
  type: "UPDATE_TITLE_TEXT",
  text: "water is fighting"
})
store.dispatch({
  type: "UPDATE_TITLE_COLOR",
  color: "#f00"
})

React-redux

react-redux則是對redux作了封裝,能夠在react中直接使用,而且提供了Providerconnect
Provider是一個組件,它接受store做爲props,而後經過context往下傳,這樣react中任何組件均可以經過context獲取store。
connect是一個函數,也是一個高階組件(HOC),經過傳入state和dispatch返回一個新的組件,它的寫法是以下:

connect(mapStateToProps, mapDispatchToProps, mergeProps, options)(component)

也能夠採用裝飾器的寫法,這須要babel的支持:

@connect(
    state,
    { func }
)

具體的很少介紹,迷你實現能夠看看這個項目:https://github.com/k-water/ma...

相關文章
相關標籤/搜索