脚手架
vue-cli => create-react-app(create-react-app xxx --typescript)
proxy接口代理
老版本vue-cli的代理在config下的config/proxyConfig中配置,然后再在config/index.js下的proxyTable中引入
module.exports = {
proxy: {
'/xxxx': {
target: 'http://xxx.com',
ws: true,
changeOrigin: true,
cookieDomainRewrite: {
'*' : ''
},
pathRewrite:{
'xxxx':'xx'
}
}
}
}
新版本的vue-cli将配置集成到了node_modules中,所以需要在根目录下建立vue.config.js,然后在其中添加相关字段
devServer: {
proxy: {
'/xxxx': {
target: 'http://xxx.com',
ws: true,
changeOrigin: true,
cookieDomainRewrite: {
'*' : ''
},
pathRewrite:{
'xxxx':'xx'
}
}
}
}
create-react-app(以下简称CRA...)脚手架的配置在根目录的config下,据其他博文所述,老版本的CRA(2版本之前)可以直接在package.json下配置跨域代理,新版本的则是在根目录下的config/webpackDevServer.config.js中配置proxy的相关内容和vue没啥区别,或在最下方before(app, server) 函数中,自行配置http-proxy-middleware,类似
const zpkProxy = require('http-proxy-middleware')
app.use(zpkProxy('/xxx', {
target:''
changeOrigin:true,
...
}
路由
vue
的路由是在一个单独的js文件new一个Router,通过配置routes数组进行页面的路由创建,然后在模板中配置<router-view>。
export default new Router({
routes: [
{
path: '/',
name: 'xxx',
meta: {},
component: xxx // 同步引入路由所需组件
// component: () => import(xxx) // 异步引入路由所需组件
}
]
})
使用动画的话,则是用<transition name='xxx' mode='xxx'>包裹router-view。
路由跳转,可以通过以下方式进行跳转:
- <router-link to="xxx">
- this.$router.push({path: 'xxx', query: {xxx: xxx}})(query换params,参数会随页面刷新而丢失)
页面可以通过this.$route.query获取路由上的参数
react
的路由则是通过创建一个Routes函数,内部通过jsx的形式来构建组件
const Routes = () => (
<HashRouter>
<Route exact path="/" render={() => <Redirect to="/nav" />} />
<Switch>
<Route path="/nav" component={Nav} />
<Route path="/index/:area" component={Index} />
<Route path="/course/:id" component={Course} />
</Switch>
</HashRouter>
)
路由跳转可以通过以下方式进行跳转
- <Link to={xxx}>
- this.props.history.push(`/course/${id}`)
路由的参数获取,可以通过以下方式获取
this.props.match.params.xxx
只有在Routes中出现的组件才能使用props获取路由中的参数,举个例子,你在首页路由下的子组件的props中找不到match字段,所以也拿不到参数
Vue中的v-if在React中如何使用
<div v-if="showDivStatus">
<div v-if="showDivStatus">
<div v-else>
// Vue中的jsx
{this.showDivStatus && <div>}
{this.showDivStatus ? <div> : <div>}
同等情况下React的jsx中
{this.state.showDivStatus && <div>}
{this.state.showDivStatus ? <div> : <div>}
Vue中的v-for在React中如何使用
<div v-for="(item, index) in divList" :key = "item.id">
{{item.name}}
</div>
同等情况下react的jsx中
{this.state.divList.map((item,index) =>
<div key={item.id}>
{item.name}
</div>
)}
Vue中的methods在React中如何使用(定义和传参)
// vue中的函数可以直接写函数名
<div @click = "clickCallback">
// 如果需要参数可以直接写成函数执行的形式
<div @click = "clickCallback(param)">
// vue的方法是定义在methods里的,并不涉及this的问题
export default {
data () {
return {
user: 'abc'
}
}
methods: {
a () {
console.log(this.user) // abc
}
}
}
React的jsx比较符合函数本身,通过bind方法严格返回一个函数,而不是通过直接的执行来传参
<div onClick = {this.clickCallback.bind(this, param)}>
// 而react的方法是写在class中的
class Index extends React.Component {
constructor (props) {
super(props)
this.state = {
user: 'abc'
}
}
// 需要箭头函数绑定this
clickCallback = (param) => {
console.log(this.state.user, param)
}
render () {
return (
<div onClick = {this.clickCallback.bind(this, param)}>
)
}
}
或者这么写
class Index extends React.Component {
constructor (props) {
super(props)
this.state = {
user: 'abc'
}
// 手动绑定this指向
this.clickCallback = this.clickCallback.bind(this);
}
clickCallback (param) {
console.log(this.state.user, param)
}
}
组件
Vue一般来说,我们都是用单独的Vue文件来作为局部组件来使用,组件调用时需要使用import引入并在components中定义,也可以使用Vue.component定义无需引入的全局组件。
React有两种组件模式:
- 带状态的class xxx extends React.Component
- 不带状态的函数组件 function xxx (props) {return(一堆jsx....)}
感觉其中最大的区别就是:
- 继承自React.Component的组件,
可能
使用到了你写了n久Vue都也许
用不到Class,反正我写了一年多Vue只在特殊的工厂模式需求下才使用es6的类,或者为了练习Class而去写Class。 - 高性能高逼格的纯函数组件+ReactHooks的辅助。。。岂不美哉!
VueX和Redux
其实上面那些都是非常基础的,无非是this、es6和jsx的问题,个人感觉VueX和Redux虽然都是一个集中的状态管理器,但是用起来真的是天壤之别,先说说两者中简单易懂的Vuex
VueX
VueX的关键词有:State、getters、mutations、commit、actions、dispatch。
然后官网盗个图
这玩意咋用呢,举一个最简单的累加器的例子,vuex的所有东西都写在一个store.js里,从项目里粘出来改的,可能手抖删错了
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
count: 0
}
const getters = {
getCount (state) {
return state.count
}
}
const mutations = {
addCount () {
state.count++
},
clearCount () {
state.count = 0
}
}
const store = new Vuex.Store({
state,
mutations,
getters
})
export default store
然后其他Vue文件中可以直接通过this.$store.count
。。。就能获取!反正我是不用严格模式,也不用getter【手动捂脸】
通过this.$store.commit
就能调用你在Store中定义的mutations来修改相应全局变量的状态。
mutations------commit是一对,负责异步操作
actions--------dispatch是一对,负责同步操作
个人根据官网图示悟出的最正确的使用姿势,应该是,getter拿state,mutations定义行为,actions在mutations外面套一层,也就是actions中commit对应的mutations,然后在其他Vue组件中疯狂的dispatch来触发actions,进而通过commit触发mutations,最后修改state的状态。
但是。。。我不这么用。。。
Redux
Redux脱离了React还是一个完整的包,所以用起来感觉也很神奇,总的来说,Redux的关键词有:Provider、actions、reducer、combineReducers、connect、container
官网盗个图。。。竟然没有!全是字,难怪比VueX复杂
官网的todoList的demo虽然没啥东西,但是对于初学者来说有点大,我们还是用一个累加器count的例子举例,代码是从项目里弹层提示相关代码里删改出来的,变量名和参数啥的可能会有些问题,请看官谅解,大体思路是没有问题的,具体步骤如下:
- 写一个action(s)
- 写一个reducer(s)和reducerCombiner
- 写一个需要Redux状态的组件counterPage
- 写一个容器包裹counterPage组件
- 在React的外层包裹一层Provider
// /src/store/actions/index.js 写一个actions
let count = 0
export const addCount = status => {
// 参数status就是dipatch调用时传递过来的参数,这里没啥用
return {
type: 'ADD_COUNT',
data: count++
}
}
/** 其他action,这里也用不到
export const clearCount = status => {
return {
type: 'CLEAR_COUNT',
data: 0
}
}**/
// /src/store/reducers/count.js 写一个reducer
const count = (state = [], action) => {
switch (action.type) {
case 'ADD_COUNT':
return action.data // 就是上方ADD_COUNT的action内count++对应的data
/**
case 'CLEAR_COUNT': // 其他action
return action.data
**/
default:
return 0
}
}
export default count
// store/reducers/index.js 写一个reducerCombiner
import { combineReducers } from 'redux'
import count from './count'
// 这里import进来的reducer的名字(count)决定了后面 容器 从state取值时使用的变量名
const xxxReducers = combineReducers({
count
})
export default xxxReducers
// 在/src/pages/counterPage.js下随便写一个组件,他的render中用到了redux中的计数
// 这里的count和addCount都需要容器来提供
render () {
return (
<div className="container">
<div className='course-block'>
<header onClick={this.props.addCount}>
<span>{this.props.count}</span>
</header>
</div>
// .......
</div>
)
}
// 在/src/container/count.js写一个包裹counterPage.js的容器,将你原来想直接使用<counterPage>组件的地方都换成<count>容器。
import { connect } from 'react-redux'
import { addCount } from '../store/actions'
import CounterPage from '../pages/counterPage'
// 这里state就是你想要的计数器的状态,初始{count:0},ownProps是counterPage的props
const mapStateToProps = (state, ownProps) => {
// 做一些你想要的处理,这里的返回值就是传递给你counterPage组件的变量
// state中的变量名取决于你combineReducers时使用的变量名
return {
count: state.count
}
}
// 这里则是定义传递给counterPage的方法,把它和dispatch关联起来
const mapDispatchToProps = (dispatch, ownProps) => {
return {
addCount: () => {
dispatch(addCount())
}
}
}
// 关联counterPage组件,把状态和方法传递进去
const CourseWithRedux = connect(
mapStateToProps,
mapDispatchToProps
)(counterPage)
export default CountWithRedux
// 最后在数据共享的外层也就是/src/index.js增加<Provider>标签
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import xxxReducers from './store/reducers'
let store = createStore(xxxReducers)
ReactDOM.render(
<Provider store={store}>
<Routes/>
</Provider>,
document.getElementById('root')
);
记得把引用过<counterPage>组件的地方变成<CountWithRedux>容器。我是觉得用起来比VueX繁琐多了。