yanyue404/blog

React & Vue 用法区别记

Opened this issue · 0 comments

1.创建组件

React

React 有两种类型的组件,分别是 functional component, class component,所以有两种定义方式:

functional component

function Test(props) {
  return <div className="container">{props.name}</div>;
}

class component

class Test extends React.Component() {
  constructor(props) {
    // super一定要写,继承React.Component
    super(props);
    // state在里面定义
    this.state = { name: 'daisy' };
  }
  // class创建的组件中 必须有render方法,且显示return内容或者null
  render() {
    return <div className="shopping-list">{this.state.name}</div>;
  }
}

Vue

全局注册

Vue.component('my-component-name', {
  /* ... */
});

局部注册

var ComponentA = {
  /* ... */
};

new Vue({
  el: '#app',
  components: {
    'component-a': ComponentA
  }
});

单文件组件

<template>
  <p class="red">{{ greeting }}</p>
  <other-component></other-component>
</template>

<script>
  import OtherComponent from './OtherComponent.vue';

  export default {
    data() {
      return {
        gretting: 'Hello'
      };
    },
    components: {
      OtherComponent
    }
  };
</script>
<style>
  .red {
    color: red;
  }
</style>

2. 模板语法

通过以下几个方面说:

  • 遍历渲染
  • 条件渲染
  • html 属性
  • 绑定事件

React

遍历渲染: map

  render() {
      var repoList = repos.map(function(repo, index) {
        return (
          <li key={index}>
            <a href={repo.html_url}>{repo.name}</a> ({repo.stargazers_count}{' '}
            stars) <br /> {repo.description}
          </li>
        );
      });
      return (
        <main>
          <ol>{repoList}</ol>
        </main>
      );
    }
  }

条件渲染:使用三目,&&,如果逻辑在复杂一点就得用函数来帮忙了

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      isHappy ? <div> yes i am  </div> : <div> no </div>
    </div>
  );
}

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
       isShow && <div>hello word</div>
    </div>
  );
}

html 属性: 跟原生一样直接写不过要换成驼峰式 tab-index => tabIndex,React 16 以后还支持自定义属性。

<div tabindex="-1" className="test" />

<div mycustomattribute="something" />

绑定事件:改成驼峰onClick这样的形式,同时传入一个函数

<button onClick={this.handleClick}>Activate Lasers</button>

阻止默认事件需要显式使用: e.preventDefault();

Vue

遍历渲染: v-for

<template>
  <li v-else-if="githubStar.length >1" v-for="(record, index) in githubStar">
    <a :href="record.html_url" :class="index<3?'red':''">
      {{ record.name }}
    </a>
    ({{ record.stargazers_count }} stars)
    <br />
    <p v-if="index<3" style="color: #000;">{{ record.description }}</p>
    <p v-else style="color: #333;">{{ record.description }}</p>
  </li>
</template>

条件渲染

  1. vue-if 系列
<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>
  1. v-show
<h1 v-show="ok">Hello!</h1>

v-if的逻辑显示不同,v-show只是简单地切换元素的 CSS 属性 display

注意,v-show 不支持 <template> 元素,也不支持 v-else

html 属性:需要用 v-bind 来指定

<!-- 完整语法 -->
<a v-bind:href="url">...</a>

<!-- 缩写 -->
<a :href="url">...</a>
<div :id="dynamicId"></div>
<img :src="imageSrc" />
<div :style="{ fontSize: size + 'px' }"></div>

绑定事件:v-on

<!-- 完整语法 -->
<button v-on:click="doThat('hello', $event)"></button>

<!-- 缩写语句 -->
<button @click="doThat('hello', $event)"></button>

事件修饰符:

<!-- 停止冒泡 -->
<button @click.stop="doThis"></button>
<!-- 阻止默认行为 -->
<button @click.prevent="doThis"></button>
<!-- 阻止默认行为,没有表达式 -->
<form @submit.prevent></form>
<!-- 点击回调只会触发一次 -->
<button v-on:click.once="doThis"></button>
<!-- 键修饰符,键别名 -->
<input @keyup.enter="onEnter" />
<!--  串联修饰符 -->
<button @click.stop.prevent="doThis"></button>

3.流通管道 Props

React

React 的 props 如果是静态的就直接传字符串,动态的就用变量{}来传,还可以传入方法(在子组件上 props 属性获取)。

class Test extends React.Component {
   constructor(super) {
     super(props);
	   this.state = { name : 'daisy'}
   }
   onClick( ) => {
      console.log("onClick");
   }
   render() {
     return (
	      <Welcome name="Sara" />;
        <Welcome name={this.state.name} />;
        <Welcome handleClick={this.onClick} />;
        // 子组件使用的时候,直接this.props.handleClick()就可以了。
	  )
   }
}

Vue

传入的值 title 为一个常量(静态 prop)时,不加 v-bind

<blog-post title="My journey with Vue"></blog-post>

传入的值 title 为一个变量(动态 prop)时,加 v-bind(此时传递的才是变量,然后 vue 会去 data 里找这个值)

<blog-post v-bind:title="titleValue"></blog-post>

传入方法的话,一样要使用 v-on,子组件要用 emit 方法来触发。

<Welcome v-on:handleClick="onClick" />;

// 子组件里要用$emit方法来触发它
<button v-on:click="$emit('handleClick')">Enlarge text</button>;

4. 内部状态 State

React

在 React,组件内部自己维护的状态叫 State,不能直接去改内部状态 state,而是通过setState

class Test extends React.Component() {
 constructor(props) {
   // super一定要写,继承React.Component
    super(props);
	// state在里面定义
	this.state = { name : 'daisy' };
  }
  changeName () => {
     this.setState({ name: 'Lily' })
  }
  render() {
    return (
      <div className="shopping-list" onClick={this.changeName}>
          {this.state.name}
      </div>
    )
  }
}

Vue

在 Vue, 组件内部自己维护的状态其实就是 Data。如果要改的话,直接在方法里通过 this 或者是通过 vue 对象来改。

var vm = new Vue({
  el: '#app',
  //  用于给 View 提供数据,相当于React的state
  data: {
    msg: 'Hello Vue'
  },
  method: {
    changeMsg: function() {
      this.msg = 'Hello daisy';
    }
  }
});

// 或者
vm.msg = 'daisy';

Vue 除了在 Data 里定义的属性之外,还额外定义计算属性跟侦听属性

// 计算属性, reversedMessage 属性将会监听 message 的改变,而自动重新计算
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    reversedMessage: function () {
      return this.message.split('').reverse().join('')
    }
  }
})

<div id="example">
  { reversedMessage }
</div>

为啥 React 不需要这个属性呢?

因为 React 有 render 函数,你可以在里面随便多定义一个变量。
每一次 this.state.message 改变的时候,都一定会调用 render 函数重新渲染,所以就相当于重新计算 reversedMessage 了。

render() {
   const reversedMessage = this.state.message.split('').reverse().join('')
    return (
      <div className="shopping-list">
        {reversedMessage}
      </div>
    )
  }

侦听属性感觉跟计算属性很像,但是他们又有不同。
侦听属性是为了可以监听到数据的改变,然后做一些异步的或者开销大的操作。

var watchExampleVM = new Vue({
  el: '#watch-example',
  data: {
    question: 'aaa'
  },
  watch: {
    // 如果 `question` 发生改变,这个函数就会运行
    question: function(newQuestion, oldQuestion) {
      this.getAnswer();
    }
  },
  methods: {
    getAnswer: function() {
      // AJax 请求
    }
  }
});

同样的问题,为啥 React 不需要这个属性呢?

因为 React 里已经有方法可以做到了。
React 15 的版本,可以通过 componentWillReceiveProps 来实现

componentWillReceiveProps(nextProps) {
    if (nextProps.id !== this.props.id) {
    	this.setState({externalData: null});
      this._loadAsyncData(nextProps.id);
    }
  }

React 16 的版本,可以通过 getDerivedStateFromPropscomponentDidUpdate 来实现。

static getDerivedStateFromProps(nextProps, prevState) {
    // Store prevId in state so we can compare when props change.
    if (nextProps.id !== prevState.prevId) {
      return {
        externalData: null,
        prevId: nextProps.id,
      };
    }
    // No state update necessary
    return null;
  }
  componentDidUpdate(prevProps, prevState) {
    if (this.state.externalData === null) {
      this._loadAsyncData(this.props.id);
    }
  }

5. 双向绑定

React

html 标签<input>, <textarea> , 和 <select> 使用受控组件,setState同步更新onChange后的 value

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  // 这里通过setState去改变state的值
  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('提交的名字: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          名字:
		  // 当input的值发生改变的时候就会调用handleChange
		  // 通过state改变value的值,所以这里的显示会随用户
		  // 的输入更新而更新
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="提交" />
      </form>
    );

Vue

vue 采用 v-model 的形式

<input v-model="message" placeholder="edit me" />
<p>Message is: {{ message }}</p>

实际上 v-model 是一个语法糖, 上面可以翻译成:

`<input :value="message" @input="message = $event.targer.value" />`

input 本身有个 oninput 事件,每当输入框发生变化,就会触发 onput,将最新的 value 传给他。

此外,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

  • input 和 textarea 元素使用 value 属性和 input 事件;
  • checkbox 和 radio 使用 checked 属性和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

v-model 不仅仅可以用在原生 html 元素上,还可以用在组件上。用在组件上的时候 v-on 用于监听事件,emit 用来触发事件。

<div id="demo">
  <currency-input v-model="price"></currentcy-input>
  // 相当于是<currency-input :value="price" v-on:input="price = arguments[0]"></currentcy-input>
  // 这里用v-on监听事件,相当于传给了子组件value,还有input方法
  <span>{{price}}</span>
</div>
Vue.component('currency-input', {
  template: `
    <span>
      <input
        ref="input"
        :value="value" // 这里将父组件传来的value赋值给input的value
        @input="$emit('input', $event.target.value)" // 这里去触发input方法
      >
    </span>
  `,
  props: ['value'],
})

var demo = new Vue({
  el: '#demo',
  data: {
    price: 100,
  }
})

6. 生命周期

React、vue 的生命周期都大同小异,主要就是创建 -> 更新 -> 销毁。具体一些名字不同而已。

参考