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="{
         '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 {
   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在数据变化时来执行异步操作时,非常有用。

原文地址:https://www.cnblogs.com/lshilin/p/10238866.html