React构建我的博客

前言

在学习react的过程当中,深深的被react的函数式编程的模式所吸引,一切皆组件,全部的东西都是JavaScript。React框架其实功能很单一,主要负责渲染的功能,可是社区很活跃,衍生出了不少优秀的库和工具。我的以为,想要作好一个项目,每每须要其余库和工具的配合,例如redux管理数据,react-router管理路由等,掌握基本的webpack配置es6语法,而后想要提升性能,还有配合react的钩子函数和immutable.js,何时组件不须要从新渲染,next.js服务端渲染等等... 一直有一个想法就是重构本身的博客,恰好这段时间放假,又恰好学习了react,因而就有了这个项目。javascript

项目地址github.com/k-water/rea…html

若是以为不错的话,您能够点右上角 "Star" 支持一下 谢谢! ^_^前端

技术栈

前端java

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

后台react

  • spring boot

此项目采用先后端分离的实现,后台接口基于RESTful规范设计,只提供数据,前端负责路由跳转,权限限制,渲染数据等。PS:因为我是个前端er,因此这里主要讲的是前端。webpack

实现的功能

  • [x] admin增删查改博客
  • [x] 博客标签
  • [x] 博客内容markdown
  • [x] 博客内容页展现目录
  • [x] 返回顶部
  • [x] markdown代码高亮
  • [x] 用户登陆注册
  • [x] 用户评论
  • [x] 响应式

TODO

  • [ ] 博客分类
  • [ ] 点击标签搜索相关博客
  • [ ] 优化首页侧边栏
  • [ ] 完善归档
  • [ ] 部署上线

效果预览

首页

内容页

用户登陆

用户评论

后台管理

我的总结

markdown渲染

在前端渲染markdown的时候遇到了一点问题,相关的包不少,可是各类包解析的结果都有差别,react周边社区推荐的是react-markdown,使用方法也很简单ios

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对代码部分实现高亮git

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

最后解析出来的是一个字符串,还须要将它插入dom中,因为安全问题,React不提倡将字符串直接插入dom中,但React保留了一个API,能够这样作:es6

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

React组件化

react的组件由dom视图和state组成,state是数据中心,它的状态决定着视图的状态。react只负责UI的渲染,与其余框架监听数据动态改变dom不一样,react采用setState来控制视图的更新。setState会自动调用render函数,触发视图的从新渲染,若是仅仅只是state数据的变化而没有调用setState,并不会触发更新。说到组件,就必须了解react组件的生命周期,官方的图解以下:github

关于这部分的解释网上有不少,能够自行查阅。而我在开发过程用的最多的就是

  • componentWillMount()
  • componentDidMount()
  • shouldComponentUpdate(nextProps, nextState) 这几个钩子函数了,关于性能优化,能够在shouldComponentUpdate上做文章,因为shouldComponentUpdate默认返回true,简单的方法能够经过比较更新先后的数据结构是否相同来判断组件是否须要从新渲染,这时候就能够采用immutable.js了。

组件之间通讯

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中直接使用,而且提供了ProviderconnectProvider是一个组件,它接受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/make-react-redux

相关文章
相关标签/搜索