React-简书项目

开学的时候学习了一个老师简书的项目,一直没总结,前两天想起来,这里总结一下。自己学的也不怎么好,可能内容有些错误的地方,大家有看到的在评论里尽管说,哈哈。

  • 下面进入正题

项目预期

  1. 可以登录,并设置是否登陆才能使用某个功能的权限
  2. 主要为首页部分的布局
  3. 有路由的相关知识,跳转到不同页面
  4. 异步数据获取

项目成果

项目实施过程

1. 创建React项目

使用 create-react-app 创建

进入React官网–Get Started–右侧Create a new React App,或者点击这里,向下就能找到安装React以及创建项目的npm方法

npm install -g create-react-app 
create-react-app my-app
cd my-app
npm start  或者 yarn start

第一行就是安装 create-react-app,这是个脚手架工具,用于创建React项目的。类似于webpack

第二行这里npm-app就是要写的React项目名称了。

然后进入这个项目文件夹,运行项目便可以了。

如果可以出现页面,有React的logo之类的表示项目创建成功

React项目结构

刚创建完应该应该把react自带的一些页面删掉或者改一下,自己再用,这里展示一下最后完成的项目的目录结构

项目结构目录

build

最上面的build 文件夹是项目最后结束后,打包之后的结果,这个包放到后端的服务器,就能访问了。

node_modules

这个里面是React运行时需要用到的各种包,组件,模块(包括第三方的)之类的,比如后面会用到的redux-thunk等等。

public

public 文件夹里的 index.html 就是整个项目页面的入口页面,可以看到和普通的HTML页面结构一模一样,<body> 中只有一个 id='root'<div>,这个<div> 便是以后项目的整个页面了。

favicon.ico 是浏览器标签栏上那个小图标。

最后的json里是一些设置文件,这个项目并没有改变这里。

src

这是整个项目最重要的部分了,几乎所有页面、逻辑、需要的文件都是在这里写的。

先说该文件夹最后面三个文件:

App.js 称为根组建,是连接所有页面的,路由的设置也在这里,可以进入不同的页面

index.js 这个是整个大的React页面的入口,其实也就是前面说的那个 id='root'div ,这里基本没有什么逻辑,主要是引入了 App.js ,然后返回给 id='root'div

style.js 其实就是CSS文件,这里面相当于给页面一个初始化的设定

common

这里面是头部导航的部分,包括logo,搜索框,右边登陆,写文章等等

里面包括了完整的store,store相当于是一个单独的空间,专门为了处理数据函数等等,同样是为了降低耦合的组件化思想。其中的对象都是imutable对象,这些后面再详细说明

pages

这里面是所有页面了,包括detail 详情页面(文章页面);home 刚进入的主页,这个页面基本连接了所有的别的页面;login 登录页面;write 写文章页面,该页面只是为了表示一下写文章需要登陆,没有其他作用。

statics

这里是一些不需要动的东西,比如引入的iconfont,需要的图片、logo等等

store

这是整个项目总体的store ,作用其实也只是为了连接所有子store

package.json

这里是项目的一些版本信息等,在创建按项目时便会产生。包括项目名,版本号,使用的模块的版本等等,还有一些其他的项目属性的东西

其他的也都是创建项目的时候会产生的,暂时不用去管。

项目详细介绍

这里就以项目的经过来介绍

整体初始化样式

引入 styled-components,使用Reset.css 见官网,对项目整体样式进行初始化

styled-components

这里使用了 styled-components 将其封装成了JS文件,原因是如果使用通常的CSS,会出现一个问题,给一个组件设置了CSS,这个组件引入的组件的某个元素如果也使用相同的className 那么该元素也会有这个CSS效果,而往往我们希望每一个组件都是单独 ,不能有较多的耦合。,所以在这里使用 styled-components 这个第三方模块,来加强组件化的思想,降低耦合 ,安装方法

yarn add styled-components

文件里的样式是通过 ES6 的语法的

首先引入 styled-components

对于全局样式

export const GlobalStyle = createGlobalStyle``;

createGlobalStyle 可以自己定义的,这个由于是全局样式,所以是需要在 App.js 中引入,使用的时候,用其包裹所有内容,或者放在最上层,用单括号。

其他的样式就直接写名称,一对 反引号 包裹就可以了

具体的还是看styled-components官方文档,需要的时候先看看,可能会有更新。

Reset.css

由于不同的浏览器对文档的渲染是不同的,使用Reset.css 可以统一格式。


简书头部区块布局

依然使用 styled-components 进行布局

common 文件夹下 header 中新建,index.js 用来书写头部区块的代码,这个文件其实相当于是一个 HTML 文件,只是使用的是React写

styled-components 在该部分需要注意的:
  1. 每个变量都需要出去,比如

    export const HeaderWrapper = styled.div`
    `;
    
  2. 对图片的引用问题,由于项目在打包的时候,不知道路径,所以需要在styled-components 中先声明某个图片的位置,后面再进行使用,比如

    import logoPic from '../../statics/nav-logo.png';
    
    export const Logo = styled.div`
       background: url(${logoPic});
    `;
    

    可以看到基本都是ES6 的写法。

  3. style.js 中定义元素的属性,看例子

    export const NavSearch = styled.input.attrs({
       placeholder: '搜索'
    })`
    	&::placeholder {
    		color: #999;
    	}
    `;
    

    这样就可以让index.js 中少一些关于属性的定义了,而改变这些属性的样式就用上面这个方法便可以。

iconfont在React中的使用

下载下来的iconfont.css 文件需要改为 JS 的格式

首先在所有iconfonturl 上加一个相对路径 ./

一般都会把iconfont 当作一个全局样式,所以也可以使用styled-components对其处理,然后将其引入到 App.js 中去,位置放在初始化的全局样式里面(下面)。

使用的时候就在要加入的页面,按照iconfont 中提供的方法加入即可。

input框动画部分

操作数据 focused 的bool 值来改变元素的 className

动画的部分使用了 react-transition-group

  1. 改变className思想 ,先定义一个变量focused,默认给false,也就相当于鼠标失焦状态,然后给搜索框绑定鼠标聚焦和失焦的函数,聚焦函数让focused的值变为``true,而这个值className中会有一个三元表达式来给元素变换className`。

  2. react-transition-group

    安装方法

    yarn add react-transition-group
    

    相关文档在github中,但是说实话这个模块并不太好用

    使用方法

    index.js
    import { CSSTransition } from 'react-transition-group';
    
    <CSSTransition
       in={focused}
       timeout={400}
       classNames="slide">
       <NavSearch>
       </NavSearch>
    </CSSTransition>
    
    style.js
    export const NavSearch = styled.input`
    	&.slide-enter {							//动画开始
       	transition: all .4s ease-in-out;
       }
       &.slide-enter-active{					 //动画执行结束
          width: 240px;
       }
       &.slide-exit{ 								 //动画结束
          transition: all .4s ease-in-out;
       }
       &.slide-exit-active{                    //结束动画
          width: 160px;
       }
    `;
    
头部数据的管理——redux

头部目前基本只有 focused 这一个数据,就以这个为例吧

  1. redux的安装

    这里顺便写一下react-redux 这个是方便在 react 中使用 redux 的模块

    yarn add redux
    yarn add react-redux
    
  2. 使用流程(之前笔记也有过)

    这里是一个比较大的项目,所以会有很多个 store ,也会有一个大的 store 用来连接分支 store

    • src 目录下创建一个 store 文件夹,里面有index.jsreducer.js

    • index.js 中引入reduxreducer

    • App.js 中引入 store

    • App.js 中引入 Provider (来自于react-redux) 。用法是用 <Provider store={store}></Provider> 包裹所有的页面,或者会使用到 store的内容的页面。作用是可以让其包裹的所有页面都可以使用到引入的 store中的数据,或者说 Provider 可以把store 中的数据提供给包裹在内的所有页面。

    • headerindex.js 中引入 connect 来自于 react-redux。 用法是在最后面使用这么一句

      export default connect(mapStateToProps, mapDispatchToProps)(Header);
      

      便可以将 store 中的数据和 Header 组件连接在一起

      mapStateToProps 中写的是从store 中取数据的方法

      mapDispatchToProps 中写的是组件要改变 store 中数据的方法

    • 将数据移到 reducer 中,将处理聚焦改变 focused 的值的方法也移到reducer

    • 将函数的派发写到mapDispatchToProps

    • 将数据的调用写到mapStateToProps 由于用了 immutable 所以这里也需要注意一下写法

    • 然后在使用数据的时候一定注意 this 的指向,现在应该都要变成 this.props 了,不过在这个项目中是将所有的都进行了聚合,在render 下一句,做了整体处理

    • redux-devtools 的使用,这是配合 redux 插件使用的,可以很清楚的看到整个项目redux的数据和逻辑

      • 官网地址 点击进入官网

      • 安装方法

        插件的在应用商店就能找到

        在代码中还有一些要注意的,在网站下面,有个 Advanced store setup 中有安装方法,复制

        在代码最外层的store 中的 index.js 中粘贴,使用方法注意以前的代码或者官网的介绍,以为涉及到多个组件。

    • store 的拆分

      已经知道,在最外层有一个store ,在每一个页面也有一个小的store 所以我们一般会把每个页面的逻辑放在自己的 store 中,而把连接所有分支 store 的总体代码写到外层那个大的 store 中。

      链接的方法就是在外面大的 store 中引入小的,逻辑写在 reducer.js 中这里需要引入一个 combineReducers ,来自于 redux-immutable ;然后其他的都需要 reducer as headerReducer 的形式来引入,这句是 ES6 中该名字的语法,原因是多个reducer 的名字一样,会出现重名的错误。

      最后再导出去便可以了,由于这里使用了 redux-immutable ,所以直接看下面代码

      import { combineReducers } from "redux-immutable";
      import { reducer as headerReducer } from '../common/header/store'; 
      
      const reducer = combineReducers({
         header: headerReducer,         // 前面header 是自己起的名字
      });
      
      export default reducer;
      

      其他的页面只要添加就可以了。

      这个代码还有一点就是第二行引入 headerReducer 的时候我们看到并没有指向 header 中的store 中的 reducer ,这是因为 header 中的 store 中的 index.js 将其导出出去,这样,这个 index.js 就相当于这个 header 的 reducer 出口文件,而大的 store 便可以直接从那里去链接了。

    • 使用 actinCreater

      使用 actinCreater 有一个好处就是可以将所有使用的 action 都放在其中,这样业务逻辑会更加清晰。

      actinCreater 是一个函数,可以返回一个对象。

      使用actinCreater 创建了action,就在 header 的index.js 中引入,这里要注意写法。

      使用 actinCreater 会出现一些字符串,会使得出错不易发现,所以再新建一个 constants.js ,将字符串都改成常量。

      最后在使用这个常量的地方都引入就可以用了。

  3. 到这里,header 中基本使用 redux 的流程就差不多了,再来总结一下

    header 中,style.js是组件的所有样式;idnex.js 中是header 部分整体的组件,有UI组件(样式部分),有 connect 组件(逻辑组件)用来存取数据等等操作;而所有的数据都存放在 store 下面的 reducer.js 中,包括后面数据库中的,需要异步请求的都在这个里面引入或者存放;

  4. immutable对象

    • 安装immutable

      yarn add immutable
      
    • 使用方法

      • 首先将 reducer 中的数据使用 fromJS 变成一个 immutable 对象
      • reducer 中使,用的时候就需要使用 immutable 的方法,比如使用 state.set('focused', true)focused 的值改变为 true
      • index.js 中也就不能使用一般的方法去获取或者发送数据了,也需要使用 immutable 的方法,比如获取数据就需要使用 state.get() 或者 state.getIn() 来获取数据,一般推荐使用后者,写起来比较少一些。
    • 其他的用法可以去 Github 查找

热门搜索异步请求
  1. 需求:通过AJAX获取数据,而且只在鼠标第一次聚焦搜索框的时候获取,往后只是使用这个数据就可以了。

  2. 实现步骤

    • reducer 中添加这个数据,为数组

    • 使用 redux-thunk 实现异步操作

      • redux-thunk 的安装

        yarn add redux-thunk
        
      • 引入方法

        在最外面的store 中引入 redux-thunk 。然后使用 redux 中的 applyMiddleware 方法,在 composeEnhancers() 中引入 thunk() 中间件。

      • 引入 axios 来实现异步操作

        yarn add axios
        

        在需要的页面引入

      • 整体使用方法即使,在 actionCreators.js 中实现异步请求的操作,大概就是导出一个函数,函数中返回一个带有 dispatch 参数的函数,函数就利用 asiox.get( ) 来获取后端的数据

      • reducer.js 中引入数据,但是由于是 immutable 的对象,所以这使用的方法有所不同

      • index.js 中,派发函数(mapDispatchToProps),获取数据(mapStateToProps)。在要展示数据的地方调用一个方法,方法就是从获取数据的地方取数据,做循环,加到该显示的地方,这里还有一个细节,比如 key 值,immutable 类型需要转换成普通数组。还有对数据分页显示,才能做到“换一换”的目的。

    • 设置只在第一次鼠标聚焦搜索框的时候获取热门搜索的列表信息

      • 在鼠标聚焦的时候,调用了 headleInputFocus() 方法,这个方法里派发了 getListaction .
      • 可以通过列表信息的 list 数据来判断是否是第一次聚焦,在调用 headleInputFocus() 的时候将 list 传递进去,然后在headleInputFocus() 方法实现的地方传入,打印一下list ,发现每次聚焦会有不同的 sizesize 为0的时候是第一次聚焦的时候,所以这里进行一个 if 判断,便可以了

路由的使用
  1. 路由安装

    yarn add react-router-dom
    
  2. 使用方法

    • App.js 中引入 react-router-dom 的其中两个组件 BrowserRouterRoute

    • 在需要使用路由的地方用 BrowserRouter 包裹 Route

      import { BrowserRouter, Route } from 'react-router-dom';
      import Home from './pages/home';
      import Detail from './pages/detail/loadable';
      
      <BrowserRouter>
         <div>
            <Header/>
            <Route path='/' exact component={Home}>
            </Route>
            <Route path='/detail/:id' exact component={Detail}>
            </Route>
         </div>
      </BrowserRouter>
      
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值