前言
本文所有vue示例基于vue2.0,react示例基于16.8+ Hook模式
指令
v-bind
<input v-bind:value="value" /> // vue
<input value={value} /> // react
v-model
<input v-model="value" /> // vue
<input v-bind:value="value" @change="(e) => emit('input', e.target.value)" /> // vue
<input value={value} onChange={(e)=>{setValue(e.target.value)}} /> // react
v-if
可以简单理解为 jsx 直接将 if 搬到html中
<div v-if="isShow"> ... </div> // vue
{isShow && <div> ... </div>} // react
v-html
可以简单理解为 jsx 直接将 if 搬到html中
<div v-html="content"></div> // vue
<div dangerouslySetInnerHTML={{__html: content}}></div> // react
v-for
可以简单理解为 jsx 直接将 if 搬到html中
// vue
<ul id="example-1">
<li v-for="item in items" :key="item.message">
{{ item.message }}
</li>
</ul>
<scritp>
export default {
data: {
items: [{ message: 'Foo' },{ message: 'Bar' }]
}
}
</script>
// react
function renderItems() {
const [items, setItems] = useState([{ message: 'Foo' },{ message: 'Bar' }])
return (
<ul id="example-1">
{items.map(item => {
return <li key={item.message}>{item.message}</li>
})}
</ul>
)
}
数据
data / watch
// vue
data() {
return {
visible: false,
}
},
watch: {
visible(val) {
// do something ...
}
},
// react
const [visible, setVisible] = useState(false)
useEffect(() => {
// do something ...
}, [visible])
ref
// vue
<template>
<input ref="inputEl" type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</template>
<scritp>
export default {
methods: {
onButtonClick: function () {
this.$refs.inputEl.focus()
}
}
}
</script>
// react
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => inputEl.current.focus();
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
事件
事件语法
jsx 中,所有事件有on开头,所有事件名称首字母大写
<input @change="(e) => this.value = e.target.value" /> // vue
<input onChange={(e)=> setValue(e.target.value)} /> // react
事件修饰符
vue事件修饰符的效果
.stop : 阻止事件冒泡,在JSX中使用 event.stopPropagation()
.prevent:阻止默认行为,在JSX中使用 event.preventDefault()
数据通信
父子通信
- 父组件传值到子组件
- 父组件调用子组件方法
- 子组件调用父组件方法
vue
// Father.vue
<template>
<div>
<Child ref="child" :fatherMsg="data" @fatherMethod="fatherMethod"></Child>
<Button @click="fatherFun">点击调用子组件方法</Button>
</div>
</template>
<script>
import Child from './Child';
export default {
data() {
return {
msg: 'father'
}
},
components: {
Child
},
methods: {
fatherMethod() {
// do something...
},
fatherFun() {
this.$refs.child.childFun(); // or $on、$refs.child.$emit("childFun")
},
}
};
</script>
// Child.vue
<template>
<div>
<div>{{FatherMsg}}</div>
<button @click="childMethod">点击调用父组件方法</button>
</div>
</template>
<script>
export default {
props: ['fatherMsg']
methods: {
childMethod() {
this.$emit('fatherMethod'); // or this.$parent.fatherMethod();
},
childFun() {
// do something...
},
}
};
</script>
react
// Father.jsx
import {useState,useRef } form React
import Child from './Child';
const Father = () => {
const child = useRef(null)
const [fatherMsg, setFatherMsg] = useState('father')
const fatherMethod = () => {
// do something
}
const fatherFun = () => {
child.current.childFun()
}
return (
<div>
<Child ref={child} fatherMsg={fatherMsg} fatherMethod={fatherMethod} />
<Button onClick={fatherFun}>点击调用子组件方法</Button>
</div>
)
}
// Child.jsx
import {forwardRef,useImperativeHandle } form React
const Child = forwardRef((props, ref) => {
const { fatherMsg, fatherMethod } = props
const childFun = () => {
// do something
}
useImperativeHandle(ref, () => ({
childFun,
}))
return (
<div>
<div>{fatherMsg}</div>
<button onClick={fatherMethod}>点击调用父组件方法</button>
</div>
)
})
多层级数据通信
vue
// 1. 通过 Vue.prototype
Vue.prototype.DEV_MODE = true
Vue.prototype.$_ = _
// 2. 通过vuex
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
history: {
state: {
allow: true,
},
mutations: {
NotAllowToPushStack: (state, allow) => {
state.allow = allow;
},
},
actions: {},
},
},
getters: {
allow: state => state.history.allow,
},
});
export default store;
react
// 1. 通过 Context 向组件树深层传递数据
const defaultHistoryContext = { allow: true}
const HistoryContext = createContext(defaultHistoryContext)
const Other = () => {
// 调用 useContext 来读取和订阅 context
const { allow } = useContext(HistoryContext)
return <div>{allow ? <div>允许</div> : <div>禁止</div>}</div>
}
const App = () => {
const [value, setValue] = useState(defaultHistoryContext)
return (
<HistoryContext.Provider value={value}>
<Other />
</HistoryContext.Provider>
)
}
// 2. 通过 recoil 实现 Context 相似功能
// 2.1 store 文件
import { atom } from 'recoil'
const historyState = atom({
key: 'history',
default: {
allow: true,
},
})
export default historyState
// 2.2 Other.jsx
import { useRecoilState } from 'recoil'
const Other = () => {
const [allow, setAllow] = useRecoilState(historyState)
return <div>{allow ? <div>允许</div> : <div>禁止</div>}</div>
}
export default Other
生命周期
vue
new Vue({
beforeCreate() {
console.log('beforeCreate');
},
created() {
console.log('created');
},
beforeMount() {
console.log('beforeMount');
},
mounted() {
console.log('mounted');
},
beforeUpdate() {
console.log('beforeUpdate');
},
updated() {
console.log('updated');
},
beforeDestroy() {
console.log('beforeDestroy');
},
destroyed() {
console.log('destroyed');
},
})
react
通过 Hook 模拟生命周期
const LifeInner = () => {
const mounted = useRef()
useEffect(() => {
if (!mounted.current) {
mounted.current = true
} else {
console.log('updated')
}
})
useEffect(() => {
console.log('mounted')
return () => {
console.log('destroyed')
}
}, [])
}
const Life = memo(LifeInner, (prevProps, nextProps) => {
console.log('shouldComponentUpdate')
// return true 更新组件 false 则不更新组件
})