1. 程式人生 > >Vue 和 React

Vue 和 React

元件

vue

<template>
  <div class="hello">
    <h1>{{msg}}</h1>
    <button @click="handleClick">click</button>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',

  // 生命週期
  created() {

  },
  mounted() {

  },
  updated() {

  },

  props: {

  },
  data() {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  },
  computed: {
    // 基於prop或data
  },
  filters: {
    // 過濾器
  },
  methods: {
    handleClick() {

    }
  },
  watch: {
    // 監控
  },
  components: {
    // 注入元件
  }
}
</script>

<style scoped>
  /* 樣式 */
</style>

react

import React, { Component } from 'react'

export default class HelloWorld extends Component {
  constructor(props) {
    super(props)
    this.state = {
      msg: 'Welcom to React'
    }
    this.handleClick = this.handleClick.bind(this)
  }

  // 生命週期
  componentWillMount() {

  }
  componentDidMount() {

  }
  componentWillUpdata(nextProps, nextState) {

  }

  handleClick() {
    // 修改狀態
    this.setState({
      msg: this.state.msg + '!'
    })
  }

  render() {
    return (
      <div className="hello">
        <h1>{this.state.msg}</h1>
        <button onClick={this.handleClick}>click</button>
      </div>
    )
  }
}

data

vue

  • 可以直接修改data
<template>
  <div class="hello">
    <h2>{{status}}</h2>
    <button @click="handleClick">click</button>
  </div>
</template>
data() {
    return {
      status: 'off'
    }
  },
methods: {
    handleClick() {
      this.status = this.status === 'off' ? 'on' : 'off'
    }
  },
  • 使用computed
<template>
  <div class="hello">
    <h2>{{status}}</h2>
    <h2>{{statusInfo}}</h2>
    <button @click="handleClick">click</button>
  </div>
</template>
data() {
  return {
    msg: 'Welcome to Your Vue.js App',
    status: 'off'
  }
},
computed: {
    statusInfo() {
      return this.status === 'off' ? '關閉' : '開啟'
    }
 },

react

  • 不能使用this.state.msg = 'newVlaue'直接修改,而是使用this.setState({}).
  constructor(props) {
    super(props)
    this.state = {
      msg: 'Welcom to React',
      status: 'off'
    }
    this.handleClick = this.handleClick.bind(this)
  }
  handleClick() {
    // 修改狀態
    this.setState({
      status: this.state.status === 'off' ? 'on' : 'off'
    })
  }

  render() {
    return (
      <div className="hello">
        <h2>{this.state.status}</h2>
        <h2>{
          this.state.status === 'off' ? '關閉' : '開啟'
        }</h2>
        <button onClick={this.handleClick}>click</button>
      </div>
    )
  }

methods

vue

在methods選項中定義

  methods: {
    handleClick() {
      // do something
    }
  },

react

  • 在元件類中定義,為了this指向元件例項,需繫結this
import React, { Component } from 'react'

export default class HelloWorld extends Component {
  constructor(props) {
    super(props)
    
    // 繫結this
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick() {
    // do something
  }

  render() {
    return (
      <div className="hello">
        <button onClick={this.handleClick}>click</button>
      </div>
    )
  }
}
  • 如果不再constructor中繫結this,可以使用箭頭函式。若考慮效能,推薦使用繫結的方式
<button onClick={() => this.handleClick()}>click</button>

方法的引數

  • vue中,直接傳入即可
<button @click="handleClick('args', $event)">click</button>
methods: {
    handleClick(args, event) {
      console.log(args)
      console.log(event)
    }
  },
  • react中,有兩種方式
<button onClick={(e) => this.handleClick('args', e)}>click</button>
<button onClick={this.handleClick.bind(this, 'args')}>click</button>

顯示和隱藏

vue

使用指令v-if或v-show(頻繁切換顯示隱藏時,使用v-show,因為v-if會重新渲染dom,會損耗效能)

<button @click="handleClick">click</button>
<p v-show="showTip">hei I am here!</p>
data() {
    return {
      showTip: false
    }
  },
methods: {
    handleClick() {
      this.showTip = !this.showTip
    }
  },

react

使用jsx表示式

import React, { Component } from 'react'

export default class HelloWorld extends Component {
  constructor(props) {
    super(props)
    this.state = {
      showTip: false
    }
    // 繫結this
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick() {
    this.setState({
      showTip: !this.state.showTip
    })
  }

  render() {
    return (
      <div className="hello">
        <button onClick={this.handleClick}>click</button>
        {
          this.state.showTip ? <p>hei I am here!</p> : null
        }
      </div>
    )
  }
}

列表

vue

使用v-for,為提高渲染效能,需提供唯一的key值,不推薦使用index,因為index所對應的值可能會不一樣。

<template>
  <div class="hello">
    <div v-for="(item, index) in list"
      :key="index"
      :style="{
        width: '70px',
        height: '50px',
        marginTop: '2px',
        background: item
      }"
    >
      {{item}}
    </div>
  </div>
</template>
  data() {
    return {
      list: [
        'red',
        'green',
        'blue',
      ]
    }
  },

react

一般使用map()遍歷陣列,渲染dom

  constructor(props) {
    super(props)
    this.state = {
      list: [
        'red',
        'green',
        'blue',
      ]
    }
  }
  
  render() {
    const { list } = this.state
    return (
      <div className="hello">
        {
          list.map((item, index) => (
            <div key={index}>{item}</div>
          ))
        }
      </div>
    )
  }

元件之間的通訊

vue

  • 父元件向子元件傳遞,通過屬性傳值,子元件使用props選項接收

父元件 App.vue

<template>
  <div id="app">
    <HelloWorld
      :message="fatherInfo"
    />
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld'

export default {
  name: 'App',
  data() {
    return {
      fatherInfo: '父元件的資訊'
    }
  },
  components: {
    HelloWorld
  }
}
</script>

子元件 HelloWorld.vue

<template>
  <div class="hello">
    <p>來自父元件的資訊:{{message}}</p>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',

  props: {
    message: {
      type: String,
      default: ''
    }
  },
}
</script>
  • 子元件向父元件傳值,通過自定義事件, this.$emit('name', args)

子元件 HelloWorld.vue

<script>
export default {
  name: 'HelloWorld',

  mounted() {
    this.$emit('sonMsg', this.sonMsg)
  },
  props: {
    message: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      sonMsg: 'I am a son ha ha!'
    }
  },
}
</script>

父元件 App.vue

<template>
  <div id="app">
    <HelloWorld
      @sonMsg="sonMsg"
    />
    <p>來自子元件的資訊: {{sonInfo}}</p>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld'

export default {
  name: 'App',
  data() {
    return {
      sonInfo: ''
    }
  },
  methods: {
    sonMsg(msg) {
      this.sonInfo = msg
    }
  },
  components: {
    HelloWorld
  }
}
</script>

react

  • 父傳子,也是通過屬性

父元件

export default class App extends Component {
  constructor() {
    super()
    this.state = {
      name: 'chen',
    }
  }

  render() {
    const { name, buttons, childName } = this.state
    return (
      <div
        <HelloWorld
          name={name}
        />
      </div>
    )
  }
}

子元件

export default class HelloWorld extends Component {
  constructor(props) {
    super(props)

  render() {
    const { name } = this.props
    return (
      <div className="hello">
        <p>來自父元件: {name}</p>
      </div>
    )
  }
}
  • 子傳父,也是通過事件
    子元件
  componentDidMount() {
    this.props.getChildren('I am a child')
  }

父元件

  constructor() {
    super()
    this.state = {
      fromChild: ''
    }
  }
  
  getChildren = (val) => {
    this.setState({
      fromChild: val
    })
  }
  
  render() {
    return (
      <div>
        <HelloWorld
          name={name}
          getChildren={this.getChildren}
        />
        <p>來自子元件:{this.state.fromChild}</p>
      </div>
    ) 
  }  

react的屬性型別檢測

import PropTypes from 'prop-types';

class App extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}

App.propTypes = {
  name: PropTypes.string
};

PropTypes傳送門

資料雙向繫結

vue

vue可以直接使用指令v-model實現資料的雙向繫結

    <input v-model="values"/>
    <p>input的值:{{values}}</p>
  data() {
    return {
      values: ''
    }
  },

react

react需要手動實現資料雙向繫結

  constructor(props) {
    super(props)
    this.state = {
      values: ''
    }
  }
  
  handleChange = (event) => {
    this.setState({
      values: event.target.value
    })
  }
  
  render() {
    return (
      <div className="hello">
        <input onChange={this.handleChange}/>
        <p>input的值:{this.state.values}</p>
      </div>
    )
  }

slot和高階元件

封裝元件時,只封裝一個外殼,如封裝一個容器,容器裡還可以裝其它元件。vue使用slot,react可以使用高階元件。

vue

Container.vue

<template>
  <div class="container">
    <slot></slot>
    <slot name="green"></slot>
    <slot name="blue"></slot>
  </div>
</template>

<script>
export default {

}
</script>

<style scoped>
.container {
  width: 200px;
  height: 200px;
  padding: 2px;
  border: 1px solid red;
}
</style>

HelloWorld.vue

<template>
  <div class="hello">
    <Container>
      <div>I have no name</div>
      <div slot="green">I am green</div>
      <div slot="blue">I am blue</div>
    </Container>
  </div>
</template>

<script>
import Container from './Container'

export default {
  name: 'HelloWorld',
  components: {
    Container
  }
}
</script>

react

  • react中也有類似的做法,{props.children}
import React, { Component } from 'react'

const Container = (props) => (
  <div>
    {props.children}
  </div>
)

export default class HelloWorld extends Component {
  render() {
    const { name } = this.props
    return (
      <div className="hello">
        <Container>
          <p>I am a child</p>
        </Container>
      </div>
    )
  }
}
  • react 中的高階元件

高階元件就是一個函式,且該函式接受一個元件作為引數,並返回一個新的元件

import React, { Component } from 'react'

const container = (Comp) => {
  return class extends Component {
    render() {
      return <Comp {...this.props} />
    }
  }
}

const Child = () => (
  <div>child</div>
)

const Container = container(Child)
export default class HelloWorld extends Component {
  render() {
    return (
      <div className="hello">
        <Container />
      </div>
    )
  }
}

其他

vue中的computed和watch

computed在DOM載入後馬上執行,watch只有在資料變化時才執行;
computed在資料未發生變化時,優先讀取快取。watch在資料變化時來執行非同步操作時,非常有用。