react学习总结-梳理
来源:互联网 发布:one域名备案 编辑:程序博客网 时间:2024/05/21 22:35
react学习总结–梳理
说明
使用 React 开发项目,仅仅靠它自己是不够的,需要花费更多的时间去学习与之配套的技术,像是:Redux、React-Router 、Gulp(或者是Webpack)、Browserify、ES6 等,下面是我梳理的使用React的简易流程
技术要求
- 开发工具 : Atom
- 构建工具 : Gulp + Browserify
- ES6 语法编写 JS,Sass 编写 CSS
- React + React-Router + Redux 创建应用
- jshint 语法检查
版本信息
- “gulp” : “^3.9.1”
- “browserify” : “^13.1.1”
- “react” : “^15.4.1”
- “react-router” : “^3.0.0”
- “redux” : “^3.6.0”
- “react-redux” : “^4.4.6”
- “react-router-redux” : “^4.0.7”
- “react-tap-event-plugin” : “^2.0.1”
项目结构
目录结构
目录设计的很烂,但是这里为了说明,还是粘出来了
app |---_data | |---a.json //存放json文件 | |---css | |---index.css //编译后的css文件 | |---img | |---a文件夹 | |---b文件夹 | |---a.jpg //根据容器组件分成各个目录 | |---js | |---actions | | |---action.js //action文件,在一个目录下 | | | |---components | | |---AppCom.js //App容器组件下的唯一子组件,负责其他子组件的嵌套 | | |---AppCom文件夹 //AppCom需要嵌套的子组件 | | |---common文件夹 //共有的组件 | | | |---containers | | |---App.js //根容器组件,router的最外层 | | |---DevTools.js //调试用组件 | | |---Home.js //普通容器组件 | | | |---reducers | | |---reducer.js //根reducer,需要引入其他所有reducer合并 | | |---appReducer.js //普通的reducer分支 | | | |---store | | |---configureStore.js //store构造器 | |---constants.js //静态常量 | |---index.js //项目入口文件 | |---routes.js //路由配置文件 | |---scss | |---_common.scss //通用样式文件 | |---index.scss //主样式文件 | |---home.scss //一般容器组件的样式文件 | |---commoncom.scss //通用组件的样式文件 | |---index.html //项目主页
注: 查资料的时候,看到有的文章上建议将一个组件的所有文件都放在一个目录,也可以试试看
|---components | |---AppCom //文件夹 | | |---index.js //组件 | | |---app.scss //样式 | | |---AppCom1.js //子组件 | | |---AppCom2.js //子组件 | | |---AppCom3.js //子组件
1.搭建开发环境
前端资源依赖于
npm
,所以请先确保已经安装了node
所有资源都是通过
npm install
安装的,Mac 需要sudo npm install
然后就是安装 Gulp 和 Browserify 了,详细的可以看 上一篇 文章
不要忘记编写.jshintrc
,要不然命令行上就都是警告了gulp 环境搭建好后,就需要下载 React 相关的文件了,我安装了这些:
- es6-promise fetch-jsonp isomorphic-fetch :这三个用来代替ajax请求数据
- react react-dom react-tap-event-plugin : React 基本使用
- react-router react-router-redux : 解决 React 应用中的路由
- redux react-redux :使用redux,管理应用状态
- redux-thunk : 异步的中间件
- redux-devtools redux-devtools-dock-monitor redux-devtools-log-monitor : redux 调试插件
我用 Atom 做编辑器,为了更好的开发也要安装相应的插件,安装了很多,这里列举一部分
- emmet atom-ctags : 都是增强代码补全的
- language-babel react redux-snippets :增强代码高亮等
- linter linter-jshint jshint :js语法检查,安装jshint时,需要注意,可以设置支持jsx语法
- autocomplete-paths autocomplete-modules :自动补全路径,还有模块
- atom-ternjs : 代码支持增强
- split-diff :检查文件差异
- 还有很多插件…
2.开始写应用
2.1 app / index.html (主页)
与一般页面的内容一样
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="ie=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0"> <title>标题</title> <!-- 引入编译后的css文件 --> <link rel="stylesheet" href="./css/app.css"> </head> <body> <!-- 项目的容器 --> <div id="app"></div> <!-- 引入编译后的js文件 --> <script src="./js/bundle.js"></script> </body> </html>
2.2 app / js / index.js (入口文件)
在这里,确定容器(#app),将组件导入容器中,创建 store ,通过,使得所有子组件都可以拿到 store 中的 state。
import React from 'react'; import ReactDOM from 'react-dom'; import {Provider} from 'react-redux'; import {Router, browserHistory} from 'react-router'; import {syncHistoryWithStore} from 'react-router-redux'; //结合store同步导航事件 import configureStore from './store/configureStore'; //引入store生成器 import reducer from './reducers/reducer'; //引入合并后的reducer import routes from './routes.js'; //引入路由配置文件 // import DevTools from './containers/DevTools'; //引入redux调试插件 import injectTapEventPlugin from 'react-tap-event-plugin'; //引入提供Touch事件的库 injectTapEventPlugin(); //初始化Touch事件 // 给增强后的store传入reducer const store = configureStore(reducer); // 创建一个增强版的history来结合store同步导航事件 const browhistory = syncHistoryWithStore(browserHistory, store); ReactDOM.render(( <Provider store={store}> <div> <Router history={browhistory} routes={routes} /> {/* <DevTools /> */} </div> </Provider> ), document.getElementById('app'));
2.3 app / js / routes.js (路由配置文件)
引入 路由配置文件
import React from 'react'; import {Route, IndexRoute} from 'react-router'; // 引入容器组件 import App from './containers/App'; import Home from './containers/Home'; import Temp from './containers/Temp'; export default ( <Route path="/" component={App}> <IndexRoute component={Home} /> <Route path="home" component={Home}/> <Route path="temp" component={Temp}/> </Route> );
2.4 app / js / constants.js (静态常量)
LOGOUT
这种完全大写的常量是用来做action.type
的, 看了很多资料,都建议将这些字符串用常量的形式保存,避免更改出错
export const LOGOUT = "LOGOUT"; export const LOGIN = "LOGIN";
2.5 app / js / store / configureStore.js ( store 生成器)
在这里是把createStore,增强了一下,加入了中间件便于处理异步操作,
compose,是redux的方法,意思是:按照顺序组合多个函数,这是函数式编程的方法,用来把多个store增强器依次执行
import { compose, createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; // 引入thunk 中间件,处理异步操作 // import createLogger from 'redux-logger'; // 利用 redux-logger打印日志 import DevTools from '../containers/DevTools'; // 引入DevTools调试组件 // const loggerMiddleware = createLogger(); // 调用日志打印方法 const middleware = [thunk]; /* 调用 applyMiddleware ,使用 middleware 来增强 createStore */ const configureStore = compose( applyMiddleware(...middleware), DevTools.instrument() )(createStore); export default configureStore;
2.6 app / js / reducers / reducer.js (合并后的reducer)
所有分支的reducer,都会被引入到这里,合并后作为创建 store 的参数
// 引入分支reducer import rootReducer from './rootReducer'; import appReducer from './appReducer'; import {combineReducers} from 'redux'; import {routerReducer} from 'react-router-redux'; // 导入routerReducer,将url信息合并到store中 // 合并到主reducer const reducer = combineReducers({ rootReducer, appReducer, routing: routerReducer, }); export default reducer;
2.7 app / js / reducers / appReducer.js (分支reducer)
一般是每个容器组件,建立一个reducer分支,管理这个容器组件内的state
const initialState = { //初始化数据 isLogin : true userId : 99990002 }; /* jshint -W138 */ export default function rootReducer(state = initialState, action) { switch (action.type) { //根据action的type属性,确定执行什么操作 case "LOGOUT": // 退出登录 return Object.assign({}, state, { isLogin : false, userId : null }); case "LOGIN": // 登录 let {isLogin,userId} = action.msg; return Object.assign({}, state, { isLogin : isLogin, userId : userId }); case "ERROR_LOGIN": console.log(action.msg); return state; default: return state; } }
2.8 app / js / actions / appAction.js (app组件的Action)
同样更多容器组件定义相应的action,使用fetch代替ajax获取数据,也可以使用其他类库:axios,jQuery等。
// 导入type类型常量 import {LOGOUT,LOGIN,ERROR_LOGIN} from '../constants.js'; require('es6-promise').polyfill(); //使支持fetch require('isomorphic-fetch'); //退出登录action export function logout() { return type:LOGOUT}; } // 登录action export function login(userId) { // 登录后或者注册后获取用户userId,根据userId获取余额信息 console.log('root get userId = '+userId); return dispatch => { fetch('../../_data/a.json').then(resp => { if (resp.status === 200) return resp.json(); throw new Error('false of json'); }).then(json => { dispatch({type:LOGIN,msg : {userId:userId,isLogin:true}}); }).catch(error => { dispatch({type:ERROR_LOGIN,msg : error}); }); }; }
2.9 app / js / containers / App.js (容器组件)
容器组件只负责处理state,和action,并将其传入子组件
import React, {Component} from 'react'; import AppCom from '../components/AppCom'; import {connect} from 'react-redux'; import { bindActionCreators } from 'redux'; import{openDatePicker,closeDatePicker,closeAndChangeDate} from '../actions/appAction'; //引入action class App extends Component { constructor(props) { super(props); } render() { return ( <AppCom {...this.props}>{this.props.children}</AppCom> ); } } // 绑定action,将其传入子组件中,子组件通过this.props.fn调用函数,就会触发action const mapDispatchToProps = dispatch => { return { openDatePicker : bindActionCreators(openDatePicker, dispatch), closeDatePicker : bindActionCreators(closeDatePicker, dispatch), closeAndChangeDate : bindActionCreators(closeAndChangeDate, dispatch) }; }; export default connect( // 转换state,将store中的state,按照需求,传入子组件,子组件通过this.props使用 state => ({ rootState:state.rootReducer, appState: state.appReducer, appRoute : state.routing}), mapDispatchToProps //绑定action多的时候就分离出去,少的话直接写在里边 )(App);
2.10 app / js / components / AppCom.js (UI组件)
展示组件,负责样式展示,数据都是从容器组件中得到
import React,{ Component } from 'react'; import BaiduMap from './HomeCom/BaiduMap'; import PullupDetails from './HomeCom/PullupDetails'; export default class HomeCom extends Component { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick() { this.props.close(); //调用父组件传递过来的事件处理函数,触发action } render() { return ( <div id="home-container"> <div className="home-nav" onClick={this.handleClick}> {this.props.appState.userId} // 使用父组件传递过来的store中的state </div> {this.props.children} </div> ); } }
- react学习总结-梳理
- React Native 学习总结
- React学习总结
- react学习总结
- react.js总结学习
- React 学习总结
- 学习React阶段性总结
- React-Native学习总结
- React-Redux 知识梳理
- React常见问题梳理
- react学习总结3--React-Router
- Android知识点总结,学习过程梳理
- Docker容器学习梳理--日常操作总结
- Phone相关知识学习总结与梳理
- react-native学习路线总结
- react学习总结4--Redux
- react native生命周期学习总结
- react-native学习路线总结
- ROSCon
- Grafana3.1.0安装步骤
- unutun 内核更换
- 从本科到研究生,看大疆工程师给你定制的机器人学习计划
- Eclipse显示行号的三种方法
- react学习总结-梳理
- Hive UDF 手册
- 关于cocos2dx在安卓编译时.so文件被删除问题
- STM32-如何使用引脚复用功能输出PWM
- 股票入门基础知识24:债务股权比率
- 过滤器和拦截器
- Activity正确的打开方式
- JavaSE系列:从源码和API分析StringBuffer(概述、构造方法)
- Android Studio相见恨晚的操作锦集