首页前端开发VUE无缝切换?从Vue到React(vue实现无缝轮播)

无缝切换?从Vue到React(vue实现无缝轮播)

时间2023-04-03 17:06:01发布访客分类VUE浏览1279
导读:本文主要分析Vue和React在开发上的区别,帮助Vue开发者快速上手React,同时也适用于前端新手入门React单文件组件 VS class组件 VS 函数组件Vue: 单文件组件<template> <div&g...

本文主要分析Vue和React在开发上的区别,帮助Vue开发者快速上手React,同时也适用于前端新手入门React

单文件组件 VS class组件 VS 函数组件

Vue: 单文件组件

template>
    
  div>
{
{
 greeting }
}
     world/div>
    
/template>
    

script>

  export default {

    data() {

      return {

        greeting: 'hello'
      }

    }

  }
    
/script>
    
style>
    
/style>

React: Class组件

class Comp extends Component {

  constructor(props) {
    
    super(props);

    this.state = {
greeting: 'hello'}
    ;

  }

  
  render() {
    
    return (
      div>
    
        div>
{
 greeting }
     world/div>
    
      /div>
    
    );

  }

}
    

官方文档

React: 函数组件(推荐)

在Vue单文件组件和React的Class组件中,我们的元素、数据变量等必须放到固定的位置,以一种固定的格式书写,而在函数组件中书写方式变得更简单,我们可以像写函数一样写组件。更重要的是,这样就不用关心那些难理解的this

const Comp = () =>
 {
    
  const [greeting, setGreeting] = useState('hello');
    
  
  return (
    div>
    
      div>
{
 greeting }
     world/div>
    
    /div>

  )
}

官方文档

双向绑定 VS 单向数据流

在Vue中我们使用v-bind、v-modal对数据进行绑定,无论是来自用户操作导致的变更,还是在某个方法里赋值都能够直接更新数据,不需要手动进行update操作。

this.data.greeting = "Hello"

而在React里需要调用set方法更新,当React感应到set触发时会再次调用render对dom进行刷新,虽然有些麻烦但这种方式可以让数据变化更加清晰易追寻。

this.state.greeting = "Hello" // 错误写法

this.setState({
greeting: 'Hello'}
    );
     // 正确写法✅
setGreeting('Hello');
     // 来自hooks的set写法 后面会介绍

React的大buff:JSX

初次接触JSX的开发者可能会感觉JSX结构混乱,因为你可以在dom元素内部直接写js逻辑,也可以在js逻辑里写dom,这就像把html和js混在一起:

import getUserType from './getUserType'

const Comp = () =>
 {
    
  const [greeting, setGreeting] = useState('hello');
    
  
  const Button = () =>
 {

    const userType = getUserType()
    
    if(userType === 0) {
    
      return button>
    去购买/button>

    }
   
    
    if(userType === 1) {
    
      return button>
    去充值/button>

    }
 
    
    return null
  }
    
  
  return (
    div>
    
      div>
{
 greeting }
     world/div>

      {
Button()}
    
    /div>

  )
}

虽然元素和逻辑的边界模糊了,但我们的组件会变得更加灵活,这样能够将一个组件分成不同的模块,当需要修改是时我们只需关注对应的函数,不用担心影响到其他部分,这对复杂的页面结构非常有用。

Hooks

是什么

上面我们在讲数据流的时候有提到,处理数据的两种方式

// 方式1
this.state = {
greeting: 'Hello'}

this.setState({
greeting: 'Hello'}
    );
     

// 方式2
const [greeting, setGreeting] = useState('hello');
    
setGreeting('Hello');

其中第二种方式的useState就是Hooks中的一种,是比较常用的Hook,除此之外还有useEffect,useRef等,每个都有着不同的功能。

为什么用

逻辑独立

以数据更新为例,简单来讲,如果不用Hooks,每次更新数据都用setSate,我们的代码里就会出现很多setState调用,setState根据入参可以一次修改一个字段,也可以一次修改多个字段,想要知道某个数据在哪里被做了怎样的修改就会变的很麻烦,甚至可能不小心多写一个字段修改了不该修改的数据。而用Hooks的useState的话,因为它在定义时会对字段创建其专用的修改函数,所以只要有这个函数的调用,就代表这个字段被做了修改。

怎么用

常用Hooks(Hooks只能在的函数组件内使用):

1.useState: 用于定义组件的 State,相当于this.state=xxx或者Vue里的data(){ return xxx}

const [greeting, setGreeting] = useState('hello');
 // greeting 默认 hello

// 点击greeting变为Hello1
div onClick={
setGreeting('Hello1')}
    >
{
greeting}
    /div>
     

2.useEffect: 通过依赖变更触发的钩子函数 ,类似Vue的watcher

// 当userId变化时调用refresh
useEffect(() =>
 {
    
  refresh();

}
    , [userId]);
    

// 进入页面时会执行init, 退出时会执行destroy
useEffect(() =>
 {
    
  init();
    
  
  return () =>
 {

     destroy()
  }

}
    , []);
    

3.useRef: 返回ref对象,.current可以获取到其原生的元素本身

const el = useRef(null);


div ref={
el}
    >
    /div>


// console.log(el.current.offsetHeight) 返回div的offsetHeight

状态管理

是什么?为什么用?

官方定义:“集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化”。
举个例子,页面里两个组件需要展示/更新userName,如果不使用状态管理,我们可以用父子组件交互的方式把userName字段和setUserName函数作为组件参数传入两个组件中,调用setUserName即触发page更新userName:

但当业务变得越来越复杂,就会陷入透传地狱!

加入状态管理后,不在涉及组件之间的参数传递,数据管理全部放在Store中管理,组件直接从Store中读取数据,修改时调用Store的修改函数修改对应数据

怎么用

Vue:Vuex

在Vue中,官方脚手架自带Vuex为我们注入好了Store,常用的state负责定义数据,mutations负责修改数据,actions负责利用mutations做一些复杂异步操作(如接口请求)

// store.js
import {
 createStore }
 from 'vuex'
const store = createStore({

  state: {

    count: 0
  }
,
  mutations: {

    setCount (state, value) {

      state.count = value
    }

  }
,
  actions: {

    addon ({
 commit, state }
) {

      const count = state.count
      commit('set', count+1)
    }

  }

}
)
// index.js
import App from './vue'
import {
 createApp }
     from 'vue'

const app = createApp(App).mount('#app');
    

// 将 store 实例作为插件安装
app.use(store)

// index.vue
template>
    
  div>
{
{
 this.$store.state.count }
}
     world/div>
    
/template>
    

script>

  export default {

    methods: {

      increment() {

        this.$store.commit('setCount', 10)
        this.$store.dispatch('setCount')
        console.log(this.$store.state.count)
      }

    }

  }
    
/script>
    
style>
    
/style>
    

React:不止是Redux

React本身并不带状态管理,状态管理对于React更像是一种普通的第三方工具,工作中不同项目可能用了Redux、mobx、rematch等不同的状态管理工具,不同工具写法会有所区别,使用者要自己区分学习,除此之外一些脚手架会自带状态管理,写法会简单些,比如Rax,为方便理解接下来以Rax的写法进行说明。

与上面所说的Vuex的state、mutations、actions对应,React里叫做state、reducers、effects。state负责定义数据,reducers负责修改数据,effects负责利用reducers做一些复杂异步操作,下面示例解释的更清楚:

// src/pages/Dashboard/models/counter.ts
const delay = (time) =>
     new Promise((resolve) =>
     setTimeout(() =>
     resolve(), time));


export default {

  // 定义 model 的初始 state
  state: {

    count: 0
  }
,
  // 定义改变该模型状态的纯函数
  reducers: {

    increment(prevState) {

      return {
 count: prevState.count + 1 }
    ;

    }
,
  }
    ,
  effects: (dispatch) =>
 ({

    async incrementAsync() {
    
      await delay(10);
    
      dispatch.counter.increment();

    }
,
  }
),
}
// src/pages/Dashboard/store.ts
import {
 createStore }
     from 'rax-app';
    
import counter from './models/counter';


const store = createStore({
 counter }
    );


export default function Dashboard() {
    
  // 使用 counter 模型
  const [counterState, counterDispatchers] = store.useModel('counter');
    

  return (
    >
    
      span>
{
counterState.count}
    /span>

      button onClick={
counterDispatchers.increment}
    >
    +/button>

      button onClick={
counterDispatchers.incrementAsync}
    >
    +/button>
    
    />
    
  );

}
    

React代码实战:开发一个TodoList

// index.jsx
import $i18n from '@alife/panda-i18n';

import React, {
 useCallback }
     from 'react';

import {
 connect }
     from 'react-redux';

import {
 Link }
     from '@ice/router';
    
import PropTypes from 'prop-types';

import {
 Form, Input }
     from 'cn-next';
    
import styles from './index.module.scss';
    

const FormItem = Form.Item;
    

const AddTodo = (props) =>
 {

  const {
 onAdd }
     = props;
    
  const onSubmit = useCallback(
    (values, errors) =>
 {

      if (!errors) {
    
        onAdd(values.text);

      }

    }
    ,
    [onAdd],
  );


  return (
    div x-class={
[styles.add]}
    >

      Form className={
styles.addForm}
 inline onSubmit={
onSubmit}
    >

        FormItem
          className={
styles.addItem}

          required
          requiredMessage={
$i18n.get({

            id: 'EnterAToDoList.other',
            dm: '请输入待办事项',
          }
)}
    
        >

          Input
            name='text'
            placeholder={
$i18n.get({

              id: 'EnterAToDoList.other',
              dm: '请输入待办事项',
            }
)}
    
          />
    
        /FormItem>

        Form.Submit className={
styles.addSubmit}
 onClick={
onSubmit}
     validate>

          {
$i18n.get({
 id: 'Add.other', dm: '添加' }
)}
    
        /Form.Submit>
    
      /Form>
    
    /div>
    
  );

}
    ;


AddTodo.propTypes = {

  onAdd: PropTypes.func,
}
    ;


AddTodo.defaultProps = {
    
  onAdd: () =>
 {
}
,
}
    ;
    

const Todos = (props) =>
 {

  const {
 list, createAsync }
     = props;
    

  // 添加
  const onAddTodo = useCallback(
    async (text) =>
 {
    
      await createAsync(text);

    }
    ,
    [createAsync],
  );


  return (
    div className={
styles.todos}
    >

      AddTodo onAdd={
onAddTodo}
     />
    
      div className='mb-30'>

        {
    list.map((item) =>
 {

          return (
            div key={
item.text}
 className={
styles.todo}
    >
    
              span>
{
item.text}
    /span>
    
            /div>
    
          );

        }
)}
    
      /div>
    
      div>
    
        Link to='/'>

          {
$i18n.get({
 id: 'ReturnToHomePage.other', dm: '返回首页' }
)}
    
        /Link>
    
      /div>
    
    /div>
    
  );

}
    ;


Todos.propTypes = {

  list: PropTypes.arrayOf(PropTypes.shape({
}
)).isRequired,
  createAsync: PropTypes.func.isRequired,
}
    ;
    

const mapState = (state) =>
 ({

  list: state.todos.list,
}
    );
    

const mapDispatch = (dispatch) =>
 ({

  createAsync: dispatch.todos.createAsync,
  doneAsync: dispatch.todos.doneAsync,
  undoneAsync: dispatch.todos.undoneAsync,
}
    );
    

export default connect(mapState, mapDispatch)(Todos);

// todo.js
export const todos = {

  state: {

    list: [
      {

        text: 'Learn typescript',
        done: true,
      }
,
      {

        text: 'Try immer',
        done: false,
      }
,
    ],
  }
,
  reducers: {

    create(state, text) {

      state.list.push({
 text, done: false }
    );
    
      return state;

    }
,
    done(state, idx) {

      if (state.list[idx]) {
    
        state.list[idx].done = true;

      }
    
      return state;

    }
,
    undone(state, idx) {

      if (state.list[idx]) {
    
        state.list[idx].done = false;

      }
    
      return state;

    }
,
  }
    ,
  effects: (dispatch) =>
 ({

    async createAsync(payload) {
    
      // 模拟异步操作
      await new Promise((resolve) =>
     setTimeout(resolve, 250));
    
      dispatch.todos.create(payload);

    }
,
    async doneAsync(payload) {
    
      // 模拟异步操作
      await new Promise((resolve) =>
     setTimeout(resolve, 250));
    
      dispatch.todos.done(payload);

    }
,
    async undoneAsync(payload) {
    
      // 模拟异步操作
      await new Promise((resolve) =>
     setTimeout(resolve, 250));
    
      dispatch.todos.undone(payload);

    }
,
  }
),
}
    ;
    

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!

存储前端开发JavaScriptrax数据管理开发者C++

若转载请注明出处: 无缝切换?从Vue到React(vue实现无缝轮播)
本文地址: https://pptw.com/jishu/938.html
Python3,5行代码,生成自动排序动图,这操作不比Excel香? 零基础快速开发Vue图书管理系统—登录注册篇(一)(vue 图书管理系统)

游客 回复需填写必要信息