资讯专栏INFORMATION COLUMN

React构建个人博客

lyning / 645人阅读

摘要:兄弟组件之间无法直接通信,它们需要利用同一层的上级作为中转站。在两个地方会用到,一是通过提交后需要拿到里面的数据,二是利用监听到发生变化后调用它来获取新的数据。

前言

在学习react的过程中,深深的被react的函数式编程的模式所吸引,一切皆组件,所有的东西都是JavaScript。React框架其实功能很单一,主要负责渲染的功能,但是社区很活跃,衍生出了很多优秀的库和工具。个人觉得,想要做好一个项目,往往需要其他库和工具的配合,例如redux管理数据,react-router管理路由等,掌握基本的webpack配置es6语法,然后想要提高性能,还有配合react的钩子函数和immutable.js,什么时候组件不需要重新渲染,next.js服务端渲染等等...
一直有一个想法就是重构自己的博客,刚好这段时间放假,又刚好学习了react,于是就有了这个项目。

项目地址:https://github.com/k-water/re...
如果觉得不错的话,您可以点右上角 "Star" 支持一下 谢谢! ^_^
技术栈

前端

react

react-redux

react-thunk

react-router

axios

eslint

maked

highlight.js

antd

es6/7/8

后台

spring boot

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

实现的功能

[x] admin增删查改博客

[x] 博客标签

[x] 博客内容markdown

[x] 博客内容页展示目录

[x] 返回顶部

[x] markdown代码高亮

[x] 用户登录注册

[x] 用户评论

[x] 响应式

TODO

[ ] 博客分类

[ ] 点击标签搜索相关博客

[ ] 优化首页侧边栏

[ ] 完善归档

效果预览 首页

内容页

用户登录

用户评论

后台管理

个人总结 markdown渲染

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

import ReactMarkdown from "react-markdown"

const input = "# This is a header

And this is a paragraph"
ReactDOM.render(
    ,
    document.getElementById("container")
)

但是发现react-markdown对表格的支持不太友好,最后采用了marked,结合highlight.js对代码部分实现高亮

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

最后解析出来的是一个字符串,还需要将它插入dom中,由于安全问题,React不提倡将字符串直接插入dom中,但React保留了一个API,可以这样做:

React组件化

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

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

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中直接使用,并且提供了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...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/107245.html

相关文章

  • react + Ant Design 的 blog-react-admin 项目的项目文档说明

    摘要:前言此项目是基于蚂蚁金服开源的之上,用全家桶的进行再次开发的,项目已经开源,项目地址在上。项目地址开源不易,如果觉得该项目不错或者对你有所帮助,欢迎到上给个,谢谢。 showImg(https://segmentfault.com/img/remote/1460000017116745); 前言 此 blog-react-admin 项目是基于 蚂蚁金服开源的 ant design p...

    chavesgu 评论0 收藏0
  • 前端相关大杂烩

    摘要:希望帮助更多的前端爱好者学习。前端开发者指南作者科迪林黎,由前端大师倾情赞助。翻译最佳实践译者张捷沪江前端开发工程师当你问起有关与时,老司机们首先就会告诉你其实是个没有网络请求功能的库。 前端基础面试题(JS部分) 前端基础面试题(JS部分) 学习 React.js 比你想象的要简单 原文地址:Learning React.js is easier than you think 原文作...

    fuyi501 评论0 收藏0
  • 从零开始编写React-Express单页博客应用(学习总结)

    摘要:单页博客应用编写总结很久之前就想写一个博客应用在一开始想要直接用和模板直接写但是暑假一开始的时候不小心入了的坑所以就一不做二不休直接用写那既然用了不写个单页应用也过意不去了不前前后后写了将近两个星期现在看来这其实是一个很容易的应用但是鉴于 React-Express单页博客应用编写总结 很久之前就想写一个博客应用.在一开始想要直接用express和ejs模板直接写, 但是暑假一开始的时...

    Jioby 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<