Getting started from vue to react
- 2021-12-04 09:09:00
- OfStack
Because the new company uses react technology stack, including Umi, Dva, Ant-design and other 1 series solutions. After a little familiarity with 1, I realized that although there are some differences, they are still quite different. Below, I will use two hot frameworks react16
&
vue2 (in active learning vue3) makes a simple comparison from design, writing style, API, life cycle and popular ecology:
Design
react | vue | 说明 | |
---|---|---|---|
定位 | 构建用户界面的js库 | 渐进式框架 | react侧重于library,vue侧重于framework |
渲染 | setState更新state的值来达到重新render视图 | 响应式数据渲染,修改了响应式数据对应的视图也进行渲染 | react需要考虑何时setState,何时render;vue只需要考虑修改数据 |
编写方式 | jsx | template | react是函数式,all in js;vue区分tempalte、script、style,提供语法糖,使用vue-loader编译 |
Component communication
react: Strict one-way data flow
Down props Up props func Multistage transfer contextFollow props, onChange/setState ()
vue: Unidirectional data flow
Down props down Upward events up (Subscribe to Publication) Multilevel delivery $attrs, $listenersThere are also various fetch component instances (VueComponent), such as: $refs, $parent, $children; Obtain superior or subordinate components recursively, such as findComponentUpward, findComponentsUpward; High-order components: provide/reject, dispatch/broadcast
react | vue | 说明 | |
---|---|---|---|
子组件数据传递 | props | props | 都是声明式 |
组件状态机 | state | data | 管理组件的状态,react使用setState更改,vue直接赋值,新属性使用$set;vue使用函数闭包特性,保证组件data的独立性,react本就是函数 |
Life cycle
react | vue | 说明 | |
---|---|---|---|
数据的初始化 | constructor | created | |
挂载 | componentDidMount | mounted | dom节点已经生成 |
更新 | componentDidUpdate | updated | react:组件更新完毕后,react只会在第1次初始化成功会进入componentDidmount,之后每次重新渲染后都会进入这个生命周期,这里可以拿到prevProps和prevState,即更新前的props和state。 vue:在数据更改导致的虚拟 DOM 重新渲染和更新完毕之后被调用 |
卸载 | componentWillUnmount | destroyed | 销毁事件 |
Event handling
react
The name of React event is small hump (camelCase) instead of pure lowercase When using JSX syntax, you need to pass in a function as an event handler instead of a string Default behavior cannot be blocked by returning false. You must explicitly use preventDefault Cannot unload the non-Element tag, otherwise it will be passed down as props
function Form() {
function handleSubmit(e) {
e.preventDefault();
console.log('You clicked submit.');
}
return (
<form onSubmit={handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}
vue
When used on ordinary elements, you can only listen for native DOM events. When used on a custom element component, you can also listen for custom events triggered by subcomponents
// Primary event
<form v-on:submit.prevent="onSubmit"></form>
// Custom Events
<my-component @my-event="handleThis(123, $event)"></my-component>
vue event modifier:
. stop-Call event. stopPropagation (). . prevent-Call event. preventDefault (). . capture-Use capture mode when adding event listeners. . self-Fires a callback only if the event is fired from the listener-bound element itself. . native-Listens for native events of the component root element. . once-Triggers only one callback. . left-(2.2. 0) Triggered only when the left mouse button is clicked. . right-(2.2. 0) Triggered only when the right mouse button is clicked. . middle-(2.2. 0) Triggered only when the middle mouse button is clicked. . passive-(2.3. 0) Add listeners in {passive: true} mode
class and style
class
react
render() {
let className = 'menu';
if (this.props.isActive) {
className += ' menu-active';
}
return <span className={className}>Menu</span>
}
vue
<div
class="static"
:class="{ active: isActive, 'text-danger': hasError }"
></div>
<div :class="[{ active: isActive }, errorClass]"></div>
style
react
<div style={{color: 'red', fontWeight: 'bold'}} />
vue
<div :style="[baseStyles, overridingStyles]"></div>
For component style, you can declare an scoped on the style tab as a component style isolation label, such as: < style lang="sass" scoped > < /style > . In the final packaging, the only 1 value of hash is added to the actual style to avoid css pollution among components
Conditional rendering
react: jsx expression, & & Or 3 yuan expression; return false means no rendering vue: The expression returns true to be rendered, and multiple v-else-if, v-else can be nested
List rendering
react: With. map, the key for 1 element is preferably a string with 1 but no 2 that this element has in the list
<ul>
{props.posts.map((post) =>
<li key={post.id}>
{post.title}
</li>
)}
</ul>
vue: In order to give Vue a hint so that it can track the identity of each node, thus reusing and reordering existing elements, you need to provide a only 1 key attribute for each item
<li v-for="item in items" :key="item.message">
{{ item.message }}
</li>
Component nesting
react
Default slot
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
Named slot
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
<SplitPane left={<Contacts />} right={<Chat />} />
vue
Default slot
// Primary event
<form v-on:submit.prevent="onSubmit"></form>
// Custom Events
<my-component @my-event="handleThis(123, $event)"></my-component>
0
Named slot
<header>
<slot name="header"></slot>
</header>
Get DOM
react: Manage focus, text selection, or media playback. Triggers a forced animation. Integrate the third party DOM library
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref={this.myRef} />;
}
}
vue: Used to register reference information for an element or subcomponent
// Primary event
<form v-on:submit.prevent="onSubmit"></form>
// Custom Events
<my-component @my-event="handleThis(123, $event)"></my-component>
3
Document structure
Umi
// Primary event
<form v-on:submit.prevent="onSubmit"></form>
// Custom Events
<my-component @my-event="handleThis(123, $event)"></my-component>
4
vue_cli
// Primary event
<form v-on:submit.prevent="onSubmit"></form>
// Custom Events
<my-component @my-event="handleThis(123, $event)"></my-component>
5
Route
Dynamic routing & Routing parameter transfer
react-router
history.push(/list?id=${id}) history.push({pathname: '/list', query: {id}}) history.push(/list/id=${id}) history.push({pathname: '/list', params: {id}})Get props. match. query/props. match. params
vue-router
this.$router.push({path: '/list', query: {id}}) this.$router.push({path: '/list', params: {id}})Get this. $router. query/this. $router. params
Nested routing
-react
// Primary event
<form v-on:submit.prevent="onSubmit"></form>
// Custom Events
<my-component @my-event="handleThis(123, $event)"></my-component>
6
Rendering sub-routes using props. children
vue-router
{
path: '/user/:id',
component: User,
children: [
{
path: 'profile',
component: UserProfile
},
{
path: 'posts',
component: UserPosts
}
]
}
<div id="app">
<router-view></router-view>
</div>
Using vue native components/ < router-view/ > Component rendering sub-route
Routing jump
umi
<NavLink exact to="/profile" activeClassName="selected">Profile</NavLink>
history.push(`/list?id=${id}`)
vue
// Primary event
<form v-on:submit.prevent="onSubmit"></form>
// Custom Events
<my-component @my-event="handleThis(123, $event)"></my-component>
9
Routing guard (login authentication, special route processing)
Umi vue-routerGlobal routing guard
Global front guard: router. beforeEach
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
Global rear guard: router. beforeEach
router.afterEach((to, from) => {
// ...
})
State management
Multiple views depend on the same 1 state or behaviors from different views need to change the same 1 state; You need to use a state manager.
dva | vuex | 说明 | |
---|---|---|---|
模块 | namespace | modules | 解决应用的所有状态会集中到1个比较大的对象,store对象可能变得相当臃肿 |
单1状态树 | state | state | 唯1数据源 |
提交状态机 | reducer | mutations | 用于处理同步操作,唯1可以修改 state 的地方 |
处理异步操作 | effects | action | 调用提交状态机更改状态树 |
Use
dva: model connect UI
// new model:models/products.js
export default {
namespace: 'products',
state: [],
reducers: {
'delete'(state, { payload: id }) {
return state.filter(item => item.id !== id);
},
},
};
//connect model
export default connect(({ products }) => ({
products,
}))(Products);
//dispatch model reduce
dispatch model reduce({
type: 'products/delete',
payload: id,
})
If there is an asynchronous operation, such as ajax request, dispath model effects, then effects calls model reduce
vuex
// new module
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
//bind UI
<input v-model="$store.state[modelesName].name"/>
//commit module mutation
store.commit('increment')
If there is an asynchronous operation, such as an ajax request, dispath module actions, and then actions calls module mutations
store.dispatch({
type: 'incrementAsync',
amount: 10
})