前段时间接触了下React,一直想要本身写一个小Demo练手。在众多应用中,考虑以后选择了简书来模仿,这段时间就利用了工做之余的时间进行开发。主要用到了React+React-Router4+Redux+Redux-thunk+Immutable。然而写文章也是能够复盘一下本身的开发过程,对本身仍是受益良多的。在这里简单叙述一下我仿简书部分布局以及功能实现的过程,仅作学习用途。
技术栈以及组件库
数据结构:html
文件结构
┣━ build // 打包文件 ┣━ public // 打包文件 ┣━ api //假数据统一存储 ┣━ detail.json //文章页数据 ┣━ headerList.json //头部热门搜索数据 ┣━ home.json //首页统一数据 ┣━ homeList.json //首页加载更多文章数据 ┣━ login.json //登陆数据 ┣━ src //开发目录 ┣━ common //公用组件 ┣━ header //头部组件 ┣━ store //Redux文件 ┣━ actionCreators.js //action建立 ┣━ constants.js //action.type常量文件 ┣━ index.js //入口文件 ┣━ reducer.js //reducer处理 ┣━ store //UI组件 ┣━ store //头部样式 ┣━ pages //页面 ┣━ detail //文章页 ┣━ ... ┣━ detail //首页 ┣━ ... ┣━ detail //登陆页 ┣━ ... ┣━ detail //写文章 ┣━ ... ┣━ statics //静态文件 ┣━ ... ┣━ store //Redux数据 ┣━ ... ┣━ App.js //入口及路由 ┣━ index.js //js文件入口 ┣━ style.js //全局样式 ┣━ .gitignore //git忽略上传文件 ┣━ package.json //模块的描述文件 ┣━ README.md //说明文件 ┣━ yarn.lock //模块的描述文件
效果预览
实现主要几个功能
用户在已登陆状态和未登陆状态的界面是不一样的,有些功能指定要在登陆状态下才会有,所以会产生状态的切换,在通常小项目中咱们可使用localStorage
来存储状态,也能够用Redux,这里我全部的数据都是使用Redux进行数据管理,在进入写文章页面调用了login组件下Redux-login状态进行判断,登陆拦截。ios
class Write extends PureComponent { render() { const { loginStatus } = this.props; console.log(loginStatus) if(loginStatus) { return ( <div>写文章</div> ) }else{ return <Redirect to="/login" /> } } componentDidMount() { } } const mapState = (state) => ({ loginStatus: state.getIn(['login','login']) });
这里在Redux中储存一个Page:1的数据,在每次点击加载更多文章时page+1,而后对page进行改变。使得每次点击page+1。git
在Home组件获取到数据后储存到Redux中,而后取出前十条数据,储存到常量中。经过点击事件对数据进行切换,同时出发动画效果。(因为使用了immutable
,因此要在循环的数据前将数据转换为不一样JS数组)github
const { focused, list, page, mouseIn, totalPage, handleMouseEnter, handleMouseLeave, hanleChangePage } = this.props; const newList = list.toJS(); //由于list目前是immutable数组,因此咱们要将他转换为普通JS数组,toJS是immutable内置方法 const pageList = []; if(newList.length){ for(let i = (page -1) * 10; i < page * 10; i++){ pageList.push( <SearchInfoItem key={newList[i]}>{newList[i]}</SearchInfoItem> ) } } if(focused || mouseIn) { return ( <SearchInfo onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} > <SearchInfoTitle> 热门搜索 <SearchInfoSwitch onClick={() => hanleChangePage(page,totalPage,this.spitIcon)}> <i ref={(icon) => {this.spitIcon = icon}} className="iconfont spin"></i> 换一批 </SearchInfoSwitch> </SearchInfoTitle> <SearchInfoList> {pageList} </SearchInfoList> </SearchInfo> ) }else { return null; } }
文章页数据的获取使用的动态路由
,经过路由传参将当前所点击文章的ID传递到文章页。json
import Detail from './pages/detail/loadable';
,否则获取不到路由所传递的参数。class Detail extends PureComponent { //dangerouslySetInnerHTML是当数据内容是HTML时使用,不会被转义为字符串 render() { const { title, content } = this.props; return ( <DetailWrapper> <Header>{title}</Header> <Content dangerouslySetInnerHTML={{__html: content}} /> </DetailWrapper> ) } componentDidMount() { let idPage = this.props.location.search; const id = idPage.substring(4) this.props.getDetail(id); //使用动态路由获取idthis.props.getDetail(this.props.match.params.id); } }
结语
因为工做比较忙,因此只作了一些基础的小功能。后面还有不少有待完善,等空余时间多了出来回慢慢进行完善。因为刚接触React,因此作的不太好,不足之处还请指教。若是你初次接触到React,或者对Demo感兴趣的话能够查看我GitHub源码redux
若是对你有帮助,能够star个人项目给我一点点的鼓励,也但愿有志同道和的能够加入一块儿讨论,我也会第一时间帮你解答。axios