react案例->新闻移动客户端--(react+redux+es6+webpack+es6的spa应用)

今天分享一个react应用,应在第一篇作品中说要做一个react+redux+xxx的应用。已经做完一部分,拿出来分享。github地址为:点我就可以咯~

这里实现了一个新闻移动站的spa。本来想写pc端的,但是比较懒,而且因为主要是react的项目,关于css和布局的细节就是糊弄人的了。T.T,这里只说关于这个项目的js部分。

这里的功能很简单,有一下几点:

1,按”心“排序

当比上一个多了,就会排到前面。

2.评论部分

新闻的评论部分类似qq空间的评论

当然,也可以点击新闻回复的哦。

=============================================

大家看到了,功能比较简单,大家clone 项目下来,直接能用的,里面已经传了我用webpack打包好的文件。

=============================================

bundle.js有3m+,这个完全是因为我加了很多库进去,比如轮播图的swiper等等,而且这些东西都是没有压缩过的。你压缩完之后,会觉得react做移动端也可以的。

就不要再问我为什么不用rn做这个。。因为我不会T.T

=============================================

要看懂本文也需要一定的基础,比如es6基础,react和redux基础。

=============================================

最后一点废话,这个东西还没有做完,只是一部分,接下来会用redux的router把它作为一个完全的spa,并且完善它的测试部分。大家期待吧~

=============================================(主文分界线)

好,接下来介绍我们的主角redux,不会的可以转到我的另一篇博文:点此

redux,昨天花了一上午,竟然看完了它全部的源码。跟你们说,它未压缩的redux.js仅有600行。angular已经1w+行了。。。

主要的是很简单,源码一看就懂,而且redux完全是fp,也就是函数式编程,它内置了一些函数式编程的例子。运用fp的库还有lodas和underscore。我将会写另一篇介绍fp与redux的博文~~

分析代码之前,先给出文件目录:

这个目录是官方example的目录,我就直接拿来用了。webpack整理的文件在public中,bootstrap没有在webpack中打包,项目中一般也用不到,其他的css和js文件都打包进去了。

其中,fonts是字体,dist存放了webpack打包后的js和css文件,public里面是轮播图js文件和图片文件。test是测试文件,现在还没写。因为不是tdd。。

剩下的actions存放的是redux的action文件。components存放的是react的组件,containers是redux如何封装组件的配置文件。reducers是redux的reducer文件,store是创建store的配置文件。

webpack主入口是index.js 它里面是添加了一些应用需要的文件,比如import Swiper from "./public/js/swiper-3.3.1.min.js"和import "./public/js/swiper.min.css",还有main.css

import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import App from './containers/App'
import configureStore from './store/configureStore'
import "./dist/main.css";

import Swiper from "./public/js/swiper-3.3.1.min.js"
import "./public/js/swiper.min.css"

import 'react-bootstrap';
const store = configureStore();

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

 

大家会看到这个项目跟上一个redux入门中的项目结构,甚至代码都类似,因为就是从上一个代码的基础上改的,不明白可以看上一篇文章

主页就不多说了,开始的页面布局和引入css文件和打包之后的js文件。

主要说一下上面提到的功能。

首先是排序。排序的原理是什么?根据心排序,心的多少。

Box是那三个新闻,这里会根据children来循环遍历出来,那个children是啥呢?是redux的store的counter数据排序之后的数据。

可以看到,我自己写了一个数据排序,根据数据的val属性排序,然后遍历,就是完成了心的特性。

state={
  counter:{
    one:{id:1,counter:0,title:"xxxx" ,time:1},
    two:{id:2,counter:0,title:"xxxx", time:1},
    three:{id:3,counter:0,title:"xxxx",time:1}
  }  
}

 

这里的counter数据,counter是心的数量。排序就不说了,看代码吧。

评论功能呢,有三个难点。1是点击回复弹出input框,2是如何回复当前的评论。比如我回复的评论必须是这个评论,而不是下一个。3就是如何把评论内容显示出来

最难的就是2了。这个还要设计一下store的数据结构。我用了一个小方法避免了添加id。这个以后再说。

1。点击弹出input框。

写react或者ng应用也不能用jquery的思想写了。点击弹出不能用click事件操作dom了。转变为react的思想,props和state。于是,要这样写。

这是根据state渲染dom阿,然后点击操作state。对了,react有个操作state的方法和初始化state的方法来着。叫getInitialState。

这里有个隐藏的坑,es6的写法不能用getInitialState。于是我就像上面这样写。es6怎么写state呢。于是我在下面的组件里又这样写:

这个state成为了这个组件的一个属性,但是确实没法用getInitialState了。不过可以用  this.setState({display: false})。这样写。来操作state

2,这个比较麻烦,首先看一下我设计的评论的store:

 var data=[
      [
         {
            text:"这里是评论1",
            huifu:["huifuxxxxxxxxxxxxx",'2xxxxxxxxxxxxxxxxxxxx','3xxxxxxxxxxxxxxxxx']
          },
         {
            text:"这里是评论1.2",
            huifu:["huifuxxxxxxxxxxxxx"]
          }
      ],[
          {
            text:"这里是评论2",
            huifu:["huifuxxxxxxxxxxxxx",'2xxxxxxxxxxxxxxxxxxxx','3xxxxxxxxxxxxxxxxx']
          }
      ],[
          {
            text:"这里是评论3",
            huifu:["huifuxxxxxxxxxxxxx",'2xxxxxxxxxxxxxxxxxxxx','3xxxxxxxxxxxxxxxxx']
          }
        ]  
    ]

 

这是整个评论的部分,包括回复。如果你要添加评论就在data[文章id].push(一样结构的评论数据),回复也是直接添加数据。

问题来了,那我们怎么保证这个回复是这个评论的呢,比如我回复123,你怎么知道是评论1的还是评论1.2(代码中的评论1.2)的呢?

这里有个小方法。我的评论框是独立于遍历之外的,就是说,你不能给他传一个文章id。那怎么办?

它取本组件的state。然后评论操作state。就是这样。评论在打开一个回复input的时候,传入本评论的id,改变本组件的state,然后就不管它的事了。

这里的小方法避免了每个评论都加一个id属性,而是一个评论数组,用的就是数组map方法的keys--

keys,是数组的键,也就是0,1,2,3用这个当作文章id。可以的!

注意这里你循环出子组件的时候,必须给他一个key的props,由于react的diff算法,必须保证子组件的位置和渲染正确,传一个key,那正好,没有id我就用这里的keys传了:

这样就没问题了。

3。显示的问题,就是上面的遍历的问题了,输入框的显示就是组件自身state的问题了。

看组件是如何显示:

{
          data[newId].map(function (items,keys) {
            return (
              <div key={keys} className="body-text">
                <h5>游客: <a onClick={that.handleClick.bind(that,keys)}>回复</a> <a href="">转发</a></h5>
                <p>{items.text}</p>
                  {
                    items.huifu.map(function (item,keyss) {
                    return ( <div key={keyss}>
                                <h5 className="huifu-user">游客回复:<a onClick={that.handleClick.bind(that,keys)} >回复</a> <a href="">转发</a></h5>
                                <p className="huifu">{item}</p>
                            </div>
                      )
                  }) 
                  } 
                  
              </div>
            )
          })
}

 

data数组是我们的数据,上面给了格式。循环遍历。

主要的是回复框的显示,操作state,这里给了他一个display属性,但是他不是true和false,而是false和keys,这个keys就是当前评论的id,这个id成为遍历的keys属性。

1的时候那张图就是根据display显示,这就不多说了。

react的优势

其实这么多文件夹,这么多js文件,用js写,逻辑又清楚又快,而用react写还带有学习成本。为啥用react写。抛开赶前端潮流不说。react的优势在于维护起来爽翻天。

js写这些逻辑刚开始写完是很清晰,我觉得过一段时间以后,想维护就很难了吧。还有一点,我想改数据的时候直接修改state,想加一个新闻就复用我的组件,根据react的虚拟dom的算法,也是不慢的。

用redux的优势就是等这个新闻项目做大,一堆一堆的js代码,如果有redux维护那就简单多了。因为纯函数的关系,redux的测试也是非常好写的。redux压缩前600行代码,加上react也是轻量级框架,这点也是很受人好评的。

用这些框架都是类似,都是数据流,他们让你用数据控制页面。ng也是如此,操作仅仅是修改数据,而不会频繁的操作dom。这是框架的优点。react在此基础上做到的低耦合,单项数据流。经常听到有react维护比较爽的呼声。-。-好维护,低耦合,轻量级。正好符合现在前端对框架的要求。于是好多人选择了react。还有JSX的写法也是比较爽的0.0react背后还有facebook撑腰。嗯,必火。。。

关于本新闻端的问题

问题在于这里:三篇新闻,每一篇当作一个事件来处理,于是--

export const LOVE_COUNTER_ONE = 'LOVE_COUNTER_ONE'
export const LOVE_COUNTER_TWO = 'LOVE_COUNTER_TWO'
export const LOVE_COUNTER_THREE = 'LOVE_COUNTER_THREE'

export const TXST_COUNTER_ONE = 'TXST_COUNTER_ONE'
export const TXST_COUNTER_TWO = 'TXST_COUNTER_TWO'
export const TXST_COUNTER_THREE = 'TXST_COUNTER_THREE'


export const HF_COUNTER_ONE = 'HF_COUNTER_ONE'
export const HF_COUNTER_TWO = 'HF_COUNTER_TWO'
export const HF_COUNTER_THREE = 'HF_COUNTER_THREE'

 

有人会说,如果100篇新闻,岂不是写n多的action?

当初在写的时候,想的是作为新闻的主页,我只放3个新闻,后面加一个更多,点开打开新闻列表页。当然,如果把这个作为新闻列表页那确实要写n多的xxx。。

那当这个新闻端改为新闻列表页怎么写呢?

首先构建一个store,把新闻id,新闻内容写进去。当然也可以组合它的评论和回复,不组合,通过id关联也是可以的。。(怎么感觉像数据库了0.0)

那这里的action就变了,改为TXST_COUNTER_NEWS,当然,这个action需要传文章的id。这个不麻烦。

reducer这里就根据文章id操作store,如果不组合评论和回复,那么,这个新闻store只需要删减新闻内容。注意新闻删了,对应的评论和回复也要删除。

组合评论和回复呢,那么也是同样,评论和回复的内容留给游客们去添加。

组件里就注意了,因为新闻组合了,那么上面就需要传一个新闻id,智能组件根据id传方法与数据给呆滞组件。。原理是这样。大家可以试着修改一下,自己动手能学到很多东西。

 还有就是webpack打包文件太大怎么办。我这个文件3m,本地加载都要143ms,这段时间3张下载完的图片并排,很丑。。

这里的减少体积大小的方法就是关闭source map,devTool也关了。重复的文件打包成common.js,还有就是压缩文件- -,当然这些都是生成环境下了。

这里测试了一下(未传到github),未压缩前可以弄到864k,当然公共库,比如Swiper可以用cdn,压缩完后这样一个数量级的应用就可以用在移动端了。

这里的操作是-删除没用的react-bootstrap,删除重复的style-loader,删除source-map及webpack hot replace及一些webpack常用插件。

还有一点,把文件作为chunk按需加载,这个貌似这个场景下还是不需要的。

需要注意的就这么多,接下来会添加路由功能,使他真正的成为spa的应用。当然,大神的标志之一---会不会写测试也会一并补齐。敬请期待~

最新更新:2016-04-25    单元测试已经补齐哦~ 博文地址:点我~    github地址:点我~

 

posted @ 2016-04-03 16:55  chenby  阅读(2689)  评论(0编辑  收藏  举报