第一次真正使用 react 去作一个小项目,可能有使用的不合理的地方,能够在 issue 中提意见,如下记录了项目实现过程当中遇到的问题。
模仿如今比较火的,淘宝返利公众号的功能,包含订单页面,已付、待反利、已反、已失效,提现页面,提现记录以及登陆页。其中部分页面&使用方式参照react-pxq项目,star 数量 6359 颇有参考意义html
1.使用 react 建立页面 √前端
2.使用 react-router-dom 实现路由 √node
3.使用 props-type 作属性检查 √react
4.搭建 mock server 模拟数据请求 √webpack
5.使用 redux 实现状态管理 √ios
6.使用 Immutablegit
7.项目中添加异步请求 √github
8.redux-thunk 中间件使用 √web
npm start
在开发环境运行chrome
浏览器打开http://localhost:3000可访问
npm run build
将工程打包到 build 目录下
npm run eject
create-react-app 自己的 webpack 配置文件存在于 node_modules/react-scripts/目录下面,可是这个目录是 node_modules/,里面的源码都是不建议修改的。create-react-app 提供了 eject 命令,用于释放这些配置。
并且 create-react-app 并不推荐你们这么作,由于这个步骤没法逆转!
npm run eject 以后,react-scripts 命令就失效了哦。由于在 node_modules/下面,都没有 react-scripts/的目录了,它以另外的形式存在于这个项目里面了。
使用 Ant Design ,相比原生 Html 能快速搭建页面,更专一于 react 相关技术的学习,其实写的是 app 端的淘宝返利一个小项目,后来发现应该使用 Ant Design Mobile 来作移动端的,不过没关系,咱们的注意力不在页面适配上。
下载 chrome 插件,方便 react 项目代码调试
react 的类型检查 PropTypes 自 React v15.5 起已弃用,请使用prop-types
JavaScript 是一门弱类型的语言,容许变量类型作隐式转换。也正是由于这个特性,JavaScript 中有不少错误都是类型错误致使的。为了减小这种错误,咱们能够在 React 中引入类型检查模块。
经常使用的检查类型有一下几种:
// 属性能够声明为 JS 原生类型 optionalArray: PropTypes.array, optionalBool: PropTypes.bool, optionalFunc: PropTypes.func, optionalNumber: PropTypes.number, optionalObject: PropTypes.object, optionalString: PropTypes.string, optionalSymbol: PropTypes.symbol
React-Redux 将全部组件分红两大类:UI 组件(presentational component)和容器组件(container component)。
UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑
React-Redux 提供 connect 方法,用于从 UI 组件生成容器组件。connect 的意思,就是将这两种组件连起来。
// CashOut.jsx import { connect } from 'react-redux' class CashOut extends Component {} export default connect( state => ({ cashInfo: state.cashInfo }), { addToCashList, resetUseMoney } )(CashOut)
为了定义业务逻辑,须要给出下面两方面的信息。
connect 方法生成容器组件之后,须要让容器组件拿到 state 对象,才能生成 UI 组件的参数。
React-Redux 提供 Provider 组件,可让容器组件拿到 state。
import { Provider } from 'react-redux' import store from '@/store/store' const render = Component => { ReactDOM.render( //绑定redux、热加载 <Provider store={store}> <Component /> </Provider>, document.getElementById('root') ) } render(Route)
使用 mocker-api coss-env
在 webpack-dev-server 的 before 钩子函数中搭建服务器
运行:npm run start-mock
访问:localhost:3000/api/getExtractList 查看数据
src 下新建 api 文件
|-src |-|-api |-|-|-api.js // 用来写接口 |-|-|-server.js // 是对axios的封装
server.js
axios 中文文档 查看 axios 配置项
import axios from 'axios' const TIMEOUT = 30000 // 设置超时时间 export default class Server { axios(method, url, params) { return new Promise((resolve, reject) => { if (typeof params !== 'object') params = {} const _option = { method, url, baseURL: 'http://localhost:3002', timeout: TIMEOUT, params: null, data: null, headers: null, withCredentials: true, //是否携带cookies发起请求 validateStatus: status => { return status >= 200 && status < 300 }, ...params } axios.request(_option).then( res => { resolve( typeof res.data === 'object' ? res.data : JSON.parse(res.data) ) }, error => { if (error.response) { reject(error.response.data) } else { reject(error) } } ) }) } }
api.js
import Server from './server' class API extends Server { async getExtractList(data = {}) { try { let result = await this.axios('post', '/api/getExtractList', data) return result } catch (err) { throw err } } } export default new API()
一个关键问题没有解决:异步操做怎么办?Action 发出之后,Reducer 当即算出 State,这叫作同步;Action 发出之后,过一段时间再执行 Reducer,这就是异步。
怎么才能 Reducer 在异步操做结束后自动执行呢?这就要用到新的工具:中间件(middleware)。
Redux 的核心概念其实很简单:将须要修改的 state 都存入到 store 里,发起一个 action 用来描述发生了什么,用 reducers 描述 action 如何改变 state tree 。建立 store 的时候须要传入 reducer,真正能改变 store 中数据的是 store.dispatch API。
import { createStore, combineReducers, applyMiddleware } from 'redux' import * as cashout from './cashout/reducer' import thunk from 'redux-thunk' let store = createStore( combineReducers({ ...cashout }), applyMiddleware(thunk) // 使用中间件 ) export default store
store/action.js
// 获取提现记录列表,保存至redux export const getCashList = () => { return async dispatch => { try { const value = await API.getCashList() // 经过dispatch来更新store dispatch({ type: GETCASHLIST, value, initLoading: false }) } catch (err) { console.error(err) } } }
<p className="my-drawer" onClick={this.goTo.bind(this,'/home')} >首页</p>
goTo (path,e){ this.setState({ visible: false, }); this.props.history.push(path) };
为了实现需求网上搜到一种,就用在项目中。看到 React 官方文档上提供的【状态提高】温度的例子,也是经过父组件提供函数,以 pros 形式传递给子组件,子组件调用 props 来修改父组件的 state。
父组件代码以下:
class CashOut extends Component { // 在父组件中定义能够改变state值得函数 transferVisible(visible) { this.setState({ visible }) } // 把transferVisible函数做为属性传递给Dialog子组件上 如 transferVisible render() { return ( <div> <Dialog title="提现成功" des="您以提现成功,可到提现记录中查看" visible={this.state.visible} transferVisible={visible => this.transferVisible(visible)} ></Dialog> </div> ) } } export default CashOut
子组件代码以下:
class Dialog extends React.Component { // 点击确认和取消时 调用props修改父组件state值 handleCancel = () => { this.props.transferVisible(false) } render() { return ( <div> <Modal title={this.props.title} visible={this.props.visible} okText="确认" cancelText="取消" onOk={this.handleCancel} onCancel={this.handleCancel} > <p>{this.props.des}</p> </Modal> </div> ) } } export default Dialog
在个人订单中,已付、待反 4 个 Tab 页面请求都会发送两次
(1)Request Method: OPTIONS
(2)Request Method: POST
跨域分为:
1.简单跨域
2.复杂跨域:复杂跨域会进行预检
复杂跨域在发送真正的请求前, 会先发送一个方法为 OPTIONS 的预请求(preflight request), 用于试探服务端是否能接受真正的请求,若是 options 得到的回应是拒绝性质的,好比 404403500 等 http 状态,就会中止 post、put 等请求的发出。
有三种方式会致使这种现象:
个人项目中出现这种状况是由于使用 POST 请求,Content-Type 设置了 application/json
解决方法:
(1)POST 请求,Content-Type 设置 application/x-www-form-urlencoded
(2)使用 qs 对 object 进行转换