1.网页依赖
Vue2:
<script src="https://unpkg/vue/dist/vue.js"></script>
Vue3:
<script src="https://unpkg/vue@next"></script>
React:
<script src="https://unpkg/react@16/umd/react.development.js"></script>
<script src="https://unpkg/react-dom@16/umd/react-dom.development.js"></script>
<!-- 生产环境中不建议使用 -->
<script src="https://unpkg/babel-standalone@6.15.0/babel.min.js"></script>
2.安装和脚手架
添加镜像和cnpm
npm config set registry https://registry.npm.taobao
npm install -g cnpm --registry=https://registry.npm.taobao
Vue2:
$ cnpm install vue
# 全局安装 vue-cli
$ cnpm install --global vue-cli
# 创建一个基于 webpack 模板的新项目
$ vue init webpack my-project
# 这里需要进行一些配置,默认回车即可
$ cd my-project
$ cnpm install
$ cnpm run dev
#打包
$ cnpm run build
Vue3:
$ cnpm install vue@next
# 全局安装 vue-cli
$ cnpm install -g @vue/cli
$ cnpm install -g @vue/cli-init
$ vue init webpack hello-vue3
# 这里需要进行一些配置,默认回车即可
#或者使用 vue create hello-vue3
# select vue 3 preset
$ cd hello-vue3
$ cnpm install
$ cnpm run dev
#打包
$ cnpm run build
React:
$ cnpm install -g create-react-app
$ create-react-app my-app
$ cd my-app/
安装依赖:cnpm install
启动项目:cnpm start
编译:cnpm run build
3.生命周期
Vue2:
beforeCreate :数据还没有挂载呢,只是一个空壳
created:这个时候已经可以使用到数据,也可以更改数据,在这里更改数据不会触发updated函数
beforeMount:虚拟dom已经创建完成,马上就要渲染,在这里也可以更改数据,不会触发updated
mounted:此时,组件已经出现在页面中,数据、真实dom都已经处理好了,事件都已经挂载好了
beforeUpdate:重新渲染之前触发,然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染
updated:数据已经更改完成,dom也重新render完成
beforeDestory:销毁前执行($destroy方法被调用的时候就会执行),一般在这里善后:清除计时器、清除非指令绑定的事件等等...
destroyed:组件的数据绑定、监听...都去掉了,只剩下dom空壳,这里也可以善后
常用的生命周期:created,mounted,beforeDestory
Vue3:
说明:由于Vue2中的beforeCreate和created生命周期的执行几乎与VUE3中的setup在同一时间执行,所以在Vue2中写在created和beforeCreate中的代码可以直接写在setup()方法中
总之:
- beforeCreate()和created()构造函数都应该写在setup()函数中
- 修改了部分钩子函数的名称
-
BeforeDestroy变成了onBeforeUnmount,destroyed变成了onUnmounted
- 新增了两个调试用钩子函数
- onRenderTracked,onRenderTriggered
例子:
<template>
<div>Hello World</div>
</template>
<script>
export default {
beforeCreate() {},
created() {},
beforeMount() {},
mounted() {},
beforeUpdate() {},
updated() {},
beforeDestroy() {},
destroyed() {},
};
</script>
React:
1) react初始化的顺序是,constructor然后是componentWillMount(相当于vue 的beforeMounted) 然后是 render渲染函数再然后是componentDidMount(相当于vue的mounted )
2) 更新的时候:componentWillUpdate、render、componentDidUpdate(跟vue一样 平时没在用到更新的钩子函数)
shouldComponentUpdate,其实在更新的时也会触发这个钩子函数,你不写默认就是true,数据改变会执行更新的钩子函数, 如果你要组织他更新的话就写这个钩子函数写成false,意思就是不让更新.
3) 销毁的时候: componentWillUnmount(vue的 话一般用beforeDestroy用来清除定时器等)
这里还有一个比较少用的钩子函数,
在父组件里面改变props传值的时候触发的:componentWillReceiveProps
例如,组件需要以props中的某个属性作为与服务器通信时的请 求参数,当这个属性值发生更新时,组件自然需要重新与服务器通信。 不难发现 componentWillReceiveProps非常适合做这个工作。
react16.4后使用了新的生命周期,使用getDerivedStateFromProps代替了旧的componentWillReceiveProps及componentWillMount。使用getSnapshotBeforeUpdate代替了旧的componentWillUpdate。
最常用的还是
componentDidMount(对vue2--mounted,vue3-onMounted)ponentWillUnmount(对vue2--beforeDestroy,vue3-onBeforeUnMount)
例子:
function component
function MyReactComponent() {
// componentDidMount
useEffect(() => {}, []);
// componentDidUpdate + componentDidMount
useEffect(() => {});
// componentWillUnmount
useEffect(() => {
return () => {...}
}, []);
// 在渲染之后但在屏幕更新之前同步运行
useLayoutEffect(() => {}, []);
return <div>Hello World</div>;
}
//Class component
class MyReactComponent extends React.Component {
static getDerivedStateFromProps(props, state) {}
componentDidMount() {}
shouldComponentUpdate(nextProps, nextState) {}
getSnapshotBeforeUpdate(prevProps, prevState) {}
componentDidUpdate(prevProps, prevState) {}
componentWillUnmount() {}
render() {
return <div>Hello World</div>;
}
}
4.基本目录
vue2:
├── build/ # Webpack 配置目录
├── dist/ # build 生成的生产环境下的项目
├── src/ # 源码目录(开发都在这里进行)
│ ├── assets/ # 放置需要经由 Webpack 处理的静态文件
│ ├── components/ # 组件
│ ├── filters/ # 过滤器
│ ├── store/ # 状态管理
│ ├── routes/ # 路由
│ ├── services/ # 服务(统一管理 XHR 请求)
│ ├── utils/ # 工具类
│ ├── views/ # 路由页面组件
│ ├── app.js # 启动文件
│ ├── index.html # 静态基页
├── static/ # 放置无需经由 Webpack 处理的静态文件
├── .babelrc # Babel 转码配置
├── .eslintignore # (配置)ESLint 检查中需忽略的文件(夹)
├── .eslintrc # ESLint 配置
├── .gitignore # (配置)需被 Git 忽略的文件(夹)
├── package.json # (这个就不用多解释了吧)
├── package-lock.json # (以记录当前状态下实际安装的各个npm package的具体来源和版本号)
Vue3:
|-node_modules -- 所有的项目依赖包都放在这个目录下
|-public -- 公共文件夹
---|favicon.ico -- 网站的显示图标
---|index.html -- 入口的html文件
|-src -- 源文件目录,编写的代码基本都在这个目录下
---|assets -- 放置静态文件的目录,比如logo.pn就放在这里
---|components -- Vue的组件文件,自定义的组件都会放到这
---|App.vue -- 根组件,这个在Vue2中也有
---|main.ts -- 入口文件,因为采用了TypeScript所以是ts结尾
---|shims-vue.d.ts -- 类文件(也叫定义文件),因为.vue结尾的文件在ts中不认可,所以要有定义文件
|-.browserslistrc -- 在不同前端工具之间公用目标浏览器和node版本的配置文件,作用是设置兼容性
|-.eslintrc.js -- Eslint的配置文件,不用作过多介绍
|-.gitignore -- 用来配置那些文件不归git管理
|-package.json -- 命令配置和包管理文件
|-README.md -- 项目的说明文件,使用markdown语法进行编写
|-tsconfig.json -- 关于TypoScript的配置文件
|-yarn.lock -- 使用yarn后自动生成的文件,由Yarn管理,安装yarn包时的重要信息存储到yarn.lock文件中
React:
主要看 public 和 src 文件夹中的文件:
public 文件夹是公共文件夹,与src最大的区别就是不会被webpack加工,用于存放一些静态文件。
- manifest.json ,扩展的配置文件
- robots.txt,爬虫爬取时应该遵守的规则
- index.html,整个项目的入口文件
- 其他文件都是图标
src 文件夹是项目存放源文件的文件夹,项目的主要内容都会存放在里面。
- App.js, 项目的主组件
- App.css,App组件的样式
- App.test.js,测试文件
- index.css,整个项目的全局样式
- index.js,JS的入口文件
- serviceWorker.js,用于使项目可以离线运行
5.入口App
Vue2:
main.js是我们的入口文件,主要作用是初始化vue实例并使用需要的插件。
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
App.vue是我们的主组件,所有页面都是在App.vue下进行切换的。可以理解为所有的路由router也是App.vue的子组件
<template>
<div id="app">
<img src="./assets/logo.png">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
Vue3+ts:
main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')
React:
// index.js
import React from 'react';
// ReactDom用于页面渲染
import ReactDOM from 'react-dom';
// index.css用于处理页面样式
import './index.css';
// App 是一个组件
import App from './App';
import * as serviceWorker from './serviceWorker';
// 用ReactDOM.render来将元素渲染到页面中
ReactDOM.render(<App />, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
6.基本组件写法
Vue2:
<template>
<h1>Hello World</h1>
</template>
<script>
export default {
name: "MyVueComponent",
};
</script>
Vue3+ts:
<template>
<div>
<h2>vue3新语法</h2>
<div>{{girl}}</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
name: "App",
setup() {
const girl = ref('番茄女孩');
return {
girl
};
},
});
</script>
比较齐全的 Vue3+ts
React:
// Class component
class MyReactComponent extends React.Component {
render() {
return <h1>Hello world</h1>;
}
}
// Function component
function MyReactComponent() {
return <h1>Hello world</h1>;
}
7.Props
Vue2:
<template>
<h1>Hello {{ name }}</h1>
</template>
<script>
export default {
name: "MyVueComponent",
props: {
name: {
type: String,
required: true,
},
mark: {
type: String,
default: "!",
},
},
};
</script>
...
<MyVueComponent name="World" />
Vue3+ts:
setup有两个参数 props 和 context
- props:接受父组件传的值
- context:vue3.x里面没有this,提供了一个context上下文属性,你可以通过这个属性去获取进行 一些 vue2.x 用this实现的操作
<template>
<h1>Hello {{ name }}</h1>
</template>
<script lang="ts">
export default {
name: "MyVueComponent",
props: {
name: {
type: String,
required: true,
default: "!",
},
},
setup(props,context){
console.log(props.name)
}
};
</script>
React:
function MyReactComponent(props) {
const { name, mark } = props;
return <h1>Hello {name}{mark}</h1>;
}
MyReactComponent.propTypes = {
name: PropTypes.string.isRequired,
mark: PropTypes.string,
}
MyReactComponent.defaultProps = {
mark: '!',
}
...
<MyReactComponent name="world">
8.事件绑定
Vue2,Vue3:
<template>
<button @click="save()">Save</button>
</template>
<script>
export default {
methods: {
save() {
console.log("save");
},
},
};
</script>
React:
//Class component
class MyReactComponent extends React.Component {
save = () => {
console.log("save");
};
render() {
return <button onClick={this.save}>Save</button>;
}
}
//Function component
function MyReactComponent() {
const save = () => {
console.log("save");
};
return <button onClick={save}>Save</button>;
}
9.自定义事件(子组件调用父组件函数,可以传参数)
Vue2,Vue3:
<template>
<button @click="deleteItem()">{{item.name}}</button>
</template>
<script>
export default {
name: "my-item",
props: {
item: Object,
},
methods: {
deleteItem() {
this.$emit("delete", this.item);
},
},
};
</script>
...
<template>
<MyItem :item="item" @delete="handleDelete" />
</template>
<script>
export default {
components: {
MyItem,
},
methods: {
handleDelete(item) { ... }
},
};
</script>
React:
function MyItem({ item, handleDelete }) {
return <button onClick={() => handleDelete(item)}>{item.name}</button>;
/*
* 应用useCallback钩子来防止在每次渲染时生成新的函数。
*
* const handleClick = useCallback(() => handleDelete(item), [item, handleDelete]);
*
* return <button onClick={handleClick}>{item.name}</button>;
*/
}
...
function App() {
const handleDelete = () => { ... }
return <MyItem item={...} handleDelete={handleDelete} />
}
10.State(Data)和Change-State(Change Data)
Vue2:
<template>
<div>
<span>{{count}}</span>
<button @click="increaseCount()">Add</button>
</div>
</template>
<script>
export default {
data() {
return { count: 0 };
},
methods: {
increaseCount() {
this.count = this.count + 1;
},
},
};
</script>
Vue3+ts:
ref 声明基础数据类型
创建一个响应式的基础类型,只能监听number、String、boolean等简单的类型,该属性一旦发生更改,都会被检测到。
<template>
<div>{{count}}</div> // 1
</template>
import {ref} from "vue"
setup(){
const count =ref(0)
count.value++ //必须要加.value
return{
count //一定要return 出去
}
}
reactive 声明响应式数据对象
<template>
<div>{{count.name}}</div> // 857
</template>
import {reactive} from "vue"
setup(){
const count =reactive({
name:'369'
})
count.name='857'
return{
count
}
}
React:
//Class component
class MyReactComponent extends React.Component {
state = {
count: 0,
};
increaseCount = () => {
this.setState({ count: this.state.count + 1 });
// 在更新之前获取当前状态,以确保我们没有使用陈旧的值
// this.setState(currentState => ({ count: currentState.count + 1 }));
};
render() {
return (
<div>
<span>{this.state.count}</span>
<button onClick={this.increaseCount}>Add</button>
</div>
);
}
}
//functiom component
function MyReactComponent() {
const [count, setCount] = useState(0);
const increaseCount = () => {
setCount(count + 1);
// setCount(currentCount => currentCount + 1);
};
return (
<div>
<span>{count}</span>
<button onClick={increaseCount}>Add</button>
</div>
);
}
11.双向绑定 (仅Vue.js,语法糖,加入界面数据->data的变化)
Vue2,Vue3
<template>
<input type="text" v-model="content" />
</template>
<script>
export default {
data() {
return { content: "" };
},
};
</script>
React:
function MyReactComponent() {
const [content, setContent] = useState("");
return (
<input
type="text"
value={content}
onChange={(e) => setContent(e.target.value)}
/>
);
}
12.计算属性computed
watch和computed各自处理的数据关系场景不同
watch擅长处理的场景:一个数据影响多个数据
computed擅长处理的场景:一个数据受多个数据影响
Vue2:
<template>
<div>{{displayName}}</div>
</template>
<script>
export default {
name: "display-name",
props: {
firstName: String,
lastName: String,
},
computed: {
displayName: function () {
return `${this.firstName} ${this.lastName}`;
},
},
};
</script>
...
<DisplayName firstName="Hello" lastName="World" />
Vue3+ts:
async setup() {
const data = reactive({
a: 10,
b: 20,
});
let sum = computed(() => data.a + data.b);
return { sum };
},
React:使用useMemo
function DisplayName({ firstName, lastName }) {
const displayName = useMemo(() => {
return `${firstName} ${lastName}`;
}, [firstName, lastName]);
return <div>{displayName}</div>;
}
...
<DisplayName firstName="Hello" lastName="World" />
13.watch
Vue2:
<template>
<div>
<span>{{count}}</span>
<button @click="increaseCount()">Add</button>
</div>
</template>
<script>
export default {
data() {
return { count: 0 };
},
methods: {
increaseCount() {
this.count = this.count + 1;
},
},
watch: {
count: function (newCount, oldCount) {
localStorage.setItem("my_count", newCount);
},
},
};
</script>
Vue3+ts:
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
//...
}
)
React:使用useEffect
function MyReactComponent() {
const [count, setCount] = useState(0);
const increaseCount = () => {
setCount((currentCount) => currentCount + 1);
};
useEffect(() => {
localStorage.setItem("my_count", newCount);
}, [count]);
return (
<div>
<span>{count}</span>
<button onClick={increaseCount}>Add</button>
</div>
);
}
class Component 可以在下面两个函数设置,也可以借助第三方库
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
14.Children-and-Slot
Slot
是对组件的扩展,通过slot插槽向组件内部指定位置传递内容,通过slot可以父子传参;
开发背景(slot出现时为了解决什么问题):
正常情况下,<Child><span style=”color:red;”>hello world</span></Child>在组件标签Child中的span标签会被组件模板template内容替换掉,当想让组件标签Child中内容传递给组件时需要使用slot插槽。
Vue2,Vue3
<template>
<div>
<slot />
</div>
</template>
<script>
export default {
name: "my-vue-component",
};
</script>
...
<MyVueComponent>Hello World</MyVueComponent>
React:
function MyReactComponent({ children }) {
return <div>{children}</div>;
}
...
<MyReactComponent>Hello World</MyReactComponent>
15.渲染HTML
Vue2,Vue3
<template>
<div v-html="html"></div>
</template>
<script>
export default {
data() {
return {
html: "<pre>...</pre>",
};
},
};
</script>
React:
function MyReactComponent() {
return <div dangerouslySetInnerHTML={{ __html: "<pre>...</pre>" }} />;
}
16.条件渲染
Vue2,Vue3
<template>
<div>
<!--v-show: 总是渲染,但根据条件更改CSS-->
<span v-show="loading">Loading...</span>
<div>
<div v-if="loading">is loading</div>
<div v-else>is loaded</div>
</div>
</div>
</template>
<script>
export default {
data() {
return { loading: true };
},
};
</script>
React:
function MyReactComponent() {
const [isLoading, setLoading] = useState(true);
return (
<div>
{isLoading && <span>Loading...</span>}
{isLoading ? <div>is loading</div> : <div>is loaded</div>}
</div>
);
}
17.列表渲染
Vue2,Vue3
<template>
<ul>
<li v-for="item in items" :key="item.id">
{{item.name}}: {{item.desc}}
</li>
</ul>
</template>
<script>
export default {
props: {
items: Array,
},
};
</script>
React:
function MyReactComponent({ items }) {
return (
<ul>
{items.map((item) => (
<li key={item.id}>
{item.name}: {item.desc}
</li>
))}
</ul>
);
}
18.Ref
Vue2,Vue3
<template>
<input ref="input" type="text" v-model="content" />
</template>
<script>
export default {
name: "autofocus-input",
data() {
return { content: "" };
},
mounted() {
this.$refs.input.focus();
},
};
</script>
React:
//Class component
class AutofocusInput extends React.Component {
constructor(props) {
super(props);
this.ref = React.createRef();
}
state = {
content: "",
};
componentDidMount() {
this.ref.current.focus();
}
setContent = (e) => {
this.setState({ content: e.target.value });
};
render() {
return (
<input
ref={this.ref}
type="text"
value={this.state.content}
onChange={this.setContent}
/>
);
}
}
//Function component
function AutofocusInput() {
const [content, setContent] = useState("");
const ref = useRef(null);
useEffect(() => {
if (ref && ref.current) {
ref.current.focus();
}
}, []);
return (
<input
ref={ref}
type="text"
value={content}
onChange={(e) => setContent(e.target.value)}
/>
);
}
19.vuex,redux
为什么不用localstorage可以代替vuex?
1).区别:vuex存储在内存,localstorage(本地存储)则以文件的方式存储在本地,永久保存;sessionstorage( 会话存储 ) ,临时保存。localStorage和sessionStorage只能存储字符串类型,对于复杂的对象可以使用ECMAScript提供的JSON对象的stringify和parse来处理
2).应用场景:vuex用于组件之间的传值,localstorage,sessionstorage则主要用于不同页面之间的传值。
3).永久性:当刷新页面(这里的刷新页面指的是 --> F5刷新,属于清除内存了)时vuex存储的值会丢失,sessionstorage页面关闭后就清除掉了,localstorage不会。
注:很多同学觉得用localstorage可以代替vuex, 对于不变的数据确实可以,但是当两个组件共用一个数据源(对象或数组)时,如果其中一个组件改变了该数据源,希望另一个组件响应该变化时,localstorage,sessionstorage无法做到,原因就是区别1。
vue2:
const store = new Vuex.Store({
state:{
loading: false,
todoList : [
{id:1,name:'11'},
{id:2,name:'22'},
{id:3,name:'33'},
],
num: 0,
},
mutations:{
setNumIs5(state){
state.num = 5
},
setNumIsWhat(state,payload){
state.num = payload.num
}
},
actions:{ <----- 增加actions属性
setNum(content){ <----- 增加setNum方法,默认第一个参数是content,其值是复制的一份store
return new Promise((resolve)=>{ <----- 返回一个promise,我们模拟一个异步操作,1秒后修改num为5
setTimeout(()=>{
contentmit('setNumIs5')
resolve()
},1000)
})
}
}
})
async mounted() {
console.log('旧值---'+this.$store.state.num);
await this.$store.dispatch('setNum') <----- actions使用dispatch进行触发,就像mutation使用commit触发一样
console.log('新值---'+this.$store.state.num);
},
Vue3与Vue2不同之处:
//创建实例的方式改变,Vue2.x为new Store , Vue3.x为createStore
//Vue2.x 中创建 store 实例
export default new Vuex.Store({
// ...
})
//Vue3.x
import Vuex from 'vuex'
export default Vuex.createStore({
state: {
count: 0
},
mutations: {
ADD (state) {
state.count++
}
},
actions: {
add ({ commit }) {
commit('ADD')
}
},
modules: {
}
})
React:
//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList';
//第一步
import {Provider} from 'react-redux';//引入react-redux
import store from './store/index';
//作用:把store提供给<Provider></Provider>所有的组件实现store共享
const App=(
<Provider store={store}>
<TodoList/>
{/*这里面的组件都有能力获取store里的数据*/}
{/*<A></A>*/}
{/*<B></B>*/}
</Provider>
);
//
// ReactDOM.render(<TodoList />, document.getElementById('root'));
ReactDOM.render(App, document.getElementById('root'));
//TodoList
import React,{Component} from 'react';
//第二步
import {connect} from 'react-redux';
class TodoList extends Component{
render(){
return(
<div>
<input
value={this.props.inputValue}//使用store传的值
onChange={this.props.changeInputValue}
/>
<button onClick={this.props.addItem}>提交</button>
<ul>
{
this.props.list.map((item,index)=>{
return <li key={index} onClick={()=>this.props.deleteItem(index)}>{item}</li>
})
}
</ul>
</div>
)
}
}
//规定映射条件 store里的state映射到组件的props里
const mapStateToProps=(state)=>{
return {
inputValue:state.inputValue,//inputValue是指组件this.props.inputValue,state.inputValue是指store里的inputValue
list:state.list,
}
};
//把store.dispatch映射到组件的props上
const mapDispatchToProps=(dispatch)=>{
return {
//把这个函数映射到组件的props上
changeInputValue(e){
const action={//1:创建action消息
type:'change_input_value',
value:e.target.value,//把输入框里的值传给store
};
dispatch(action);//2:把这个消息传给store处理
},
addItem(){
const action={
type:'add_item',
};
dispatch(action);
},
deleteItem(index){
const action={
type:'delete_item',
index:index,
};
dispatch(action);
}
}
};
//目的:使TodoList和store做链接
export default connect(mapStateToProps,mapDispatchToProps)(TodoList);
//store/index.js
import {createStore} from 'redux';
import reducer from './reducer';
const store=createStore(reducer);
export default store;
//store/reducer.js
const defaultState={//创建一个默认state
inputValue:'',
list:[],
};
export default (state=defaultState,action)=>{
//3:处理store自动传过来的action消息
if(action.type==='change_input_value'){
const newState=JSON.parse(JSON.stringify(state));//对原有数据进行深拷贝、
newState.inputValue=action.value;
return newState;//4:reducer把newState传给store,store进行更新处理
}
if (action.type==='add_item'){
const newState=JSON.parse(JSON.stringify(state));//对原有数据进行深拷贝、
newState.list.push(newState.inputValue);
newState.inputValue='';
return newState;
}
if (action.type==='delete_item'){
const newState=JSON.parse(JSON.stringify(state));//对原有数据进行深拷贝、
newState.list.splice(action.index,1);//删除从索引开始的1个
return newState;
}
return state;
}
用户发出 Action,Reducer 函数算出新的 State,View 重新渲染。但是,一个关键问题没有解决:异步操作怎么办?Action 发出以后,Reducer 立即算出 State,这叫做同步;Action 发出以后,过一段时间再执行 Reducer,这就是异步。
怎么才能 Reducer 在异步操作结束后自动执行呢?这就要用到新的工具:中间件. redux-thunk。
20.route
Vue2:
//home.vue
<template>
<div>
<h1>home</h1>
<p>{{msg}}</p>
</div>
</template>
<script>
export default {
data () {
return {
msg: "我是home 组件"
}
}
}
</script>
//App.vue
<template>
<div id="app">
<img src="./assets/logo.png">
<header>
<!-- router-link 定义点击后导航到哪个路径下 -->
<router-link to="/home">Home</router-link>
</header>
<!-- 对应的组件内容渲染到router-view中 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
}
</script>
//index.js
import Vue from "vue";
import VueRouter from "vue-router";
// 引入组件
import home from "./home.vue";
import about from "./about.vue";
// 要告诉 vue 使用 vueRouter
Vue.use(VueRouter);
const routes = [
{
path:"/home",
component: home
}
]
var router = new VueRouter({
routes
})
export default router;
//main.js
import Vue from 'vue'
import App from './App.vue'
// 引入路由
import router from "./router.js" // import router 的router 一定要小写, 不要写成Router, 否则报 can't match的报错
new Vue({
el: '#app',
router, // 注入到根实例中
render: h => h(App)
})
//router.js
const routes = [
{
path:"/home",
component: home
},
{
path: "/about",
component: about
},
// 重定向
{
path: '/',
redirect: '/home'
}
]
Vue3与Vue2不同点:
//Vue2.x
//通过this获取router实例
export default{
mounted() {
this.getRouter();
},
methods: {
getRouter() {
console.log(this.$route);
console.log(this.$router);
},
},
}
//Vue3.x
//第一种 通过使用 getCurrentInstance 方法获取当前组件实例
import { getCurrentInstance } from "vue";
export default {
setup(props, context) {
const { ctx } = getCurrentInstance();
console.log(ctx.$router.currentRoute.value);
},
};
//第二种通过userRoute和userRouter
import { useRoute, useRouter } from "vue-router";
export default {
setup(props, context) {
const currRoute = useRoute();
const currRouter = useRouter();
console.log(currRoute);
console.log(currRouter);
},
};
React 和Vue差不多:
//Test.js
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import Index from '../pages/Index'
import List from './List'
class Test extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div>
<Router>
<ul>
<li>
<Link to="/">首页</Link>
</li>
<Route path="/" exact component={Index}></Route>
</ul>
</Router>
</div>
);
}
}
export default Test;
//index.js
import React, { Component } from 'react';
class Index extends Component {
constructor(props) {
super(props);
this.state = { }
}
render() {
return (
<div>
index
</div>
);
}
}
export default Index;
更多推荐
Vue2,Vue3,React的对比
发布评论