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的对比