React.js和Vue.js的语法并列比较
source link: http://mp.weixin.qq.com/s?__biz=MzI0MDIwNTQ1Mg%3D%3D&%3Bmid=2676493160&%3Bidx=1&%3Bsn=cc87d24be24277c38e1e34670fc0d00b
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
React.js和Vue.js都是很好的框架。而且Next.js和Nuxt.js甚至将它们带入了一个新的高度,这有助于我们以更少的配置和更好的可维护性来创建应用程序。但是,如果你必须经常在框架之间切换,在深入探讨另一个框架之后,你可能会轻易忘记另一个框架中的语法。在本文中,我总结了这些框架的基本语法和方案,然后并排列出。我希望这可以帮助我们尽快掌握语法,不过限于篇幅,这篇文章只 比较React.js和Vue.js ,下一篇再谈Next.js个Nuxt.js。
Github
https://github.com/oahehc/react-vue-comparison
Render
React.js
ReactDOM.render(<App />, document.getElementById("root"));
Vue.js
new Vue({ render: (h) => h(App), }).$mount("#root");
基本组件
React.js
Class component
class MyReactComponent extends React.Component { render() { return <h1>Hello world</h1>; } }
Function component
function MyReactComponent() { return <h1>Hello world</h1>; }
Vue.js
<template> <h1>Hello World</h1> </template> <script> export default { name: "MyVueComponent", }; </script>
Prop
React.js
function MyReactComponent(props) { const { name, mark } = props; return <h1>Hello {name}{mark}</h1>; } MyReactComponent.propTypes = { name: PropTypes.string.isRequired, mark: PropTypes.string, } MyReactComponent.defaultProps = { mark: '!', } ... <MyReactComponent name="world">
Vue.js
<template> <h1>Hello {{ name }}</h1> </template> <script> export default { name: "MyVueComponent", props: { name: { type: String, required: true, }, mark: { type: String, default: "!", }, }, }; </script> ... <MyVueComponent name="World" />
事件绑定
React.js
Class component
class MyReactComponent extends React.Component { save = () => { console.log("save"); }; render() { return <button onClick={this.save}>Save</button>; } }
Function component
function MyReactComponent() { const save = () => { console.log("save"); }; return <button onClick={save}>Save</button>; }
Vue.js
<template> <button @click="save()">Save</button> </template> <script> export default { methods: { save() { console.log("save"); }, }, }; </script>
自定义事件
React.js
function MyItem({ item, handleDelete }) { return <button onClick={() => handleDelete(item)}>{item.name}</button>; /* * 应用useCallback钩子来防止在每次渲染时生成新的函数。 * * const handleClick = useCallback(() => handleDelete(item), [item, handleDelete]); * * return <button onClick={handleClick}>{item.name}</button>; */ } ... function App() { const handleDelete = () => { ... } return <MyItem item={...} handleDelete={handleDelete} /> }
Vue.js
<template> <button @click="deleteItem()">{{item.name}}</button> </template> <script> export default { name: "my-item", props: { item: Object, }, methods: { deleteItem() { this.$emit("delete", this.item); }, }, }; </script> ... <template> <MyItem :item="item" @delete="handleDelete" /> </template> <script> export default { components: { MyItem, }, methods: { handleDelete(item) { ... } }, }; </script>
State
React.js
Class component
class MyReactComponent extends React.Component { state = { name: 'world, } render() { return <h1>Hello { this.state.name }</h1>; } }
Function component
function MyReactComponent() { const [name, setName] = useState("world"); return <h1>Hello {name}</h1>; }
Vue.js
<template> <h1>Hello {{ name }}</h1> <!-- 使用组件状态作为prop --> <my-vue-component :name="name"> </template> <script> export default { data() { return { name: "world" }; }, }; </script>
Change-State
React.js
Class component
class MyReactComponent extends React.Component { state = { count: 0, }; increaseCount = () => { this.setState({ count: this.state.count + 1 }); // 在更新之前获取当前状态,以确保我们没有使用陈旧的值 // this.setState(currentState => ({ count: currentState.count + 1 })); }; render() { return ( <div> <span>{this.state.count}</span> <button onClick={this.increaseCount}>Add</button> </div> ); } }
Function component
function MyReactComponent() { const [count, setCount] = useState(0); const increaseCount = () => { setCount(count + 1); // setCount(currentCount => currentCount + 1); }; return ( <div> <span>{count}</span> <button onClick={increaseCount}>Add</button> </div> ); }
Vue.js
<template> <div> <span>{{count}}</span> <button @click="increaseCount()">Add</button> </div> </template> <script> export default { data() { return { count: 0 }; }, methods: { increaseCount() { this.count = this.count + 1; }, }, }; </script>
双向绑定 (仅Vue.js)
React.js
React没有双向绑定,因此我们需要自己处理数据流
function MyReactComponent() { const [content, setContent] = useState(""); return ( <input type="text" value={content} onChange={(e) => setContent(e.target.value)} /> ); }
Vue.js
<template> <input type="text" v-model="content" /> </template> <script> export default { data() { return { content: "" }; }, }; </script>
计算属性
React.js
React.js没有计算属性,但我们可以通过react hook轻松实现
function DisplayName({ firstName, lastName }) { const displayName = useMemo(() => { return `${firstName} ${lastName}`; }, [firstName, lastName]); return <div>{displayName}</div>; } ... <DisplayName firstName="Hello" lastName="World" />
Vue.js
<template> <div>{{displayName}}</div> </template> <script> export default { name: "display-name", props: { firstName: String, lastName: String, }, computed: { displayName: function () { return `${this.firstName} ${this.lastName}`; }, }, }; </script> ... <DisplayName firstName="Hello" lastName="World" />
Watch
React.js
React.js没有 watch
属性,但是我们可以通过react hook轻松实现
function MyReactComponent() { const [count, setCount] = useState(0); const increaseCount = () => { setCount((currentCount) => currentCount + 1); }; useEffect(() => { localStorage.setItem("my_count", newCount); }, [count]); return ( <div> <span>{count}</span> <button onClick={increaseCount}>Add</button> </div> ); }
Vue.js
<template> <div> <span>{{count}}</span> <button @click="increaseCount()">Add</button> </div> </template> <script> export default { data() { return { count: 0 }; }, methods: { increaseCount() { this.count = this.count + 1; }, }, watch: { count: function (newCount, oldCount) { localStorage.setItem("my_count", newCount); }, }, }; </script>
Children-and-Slot
React.js
function MyReactComponent({ children }) { return <div>{children}</div>; } ... <MyReactComponent>Hello World</MyReactComponent>
Vue.js
<template> <div> <slot /> </div> </template> <script> export default { name: "my-vue-component", }; </script> ... <MyVueComponent>Hello World</MyVueComponent>
渲染HTML
React.js
function MyReactComponent() { return <div dangerouslySetInnerHTML={{ __html: "<pre>...</pre>" }} />; }
Vue.js
<template> <div v-html="html"></div> </template> <script> export default { data() { return { html: "<pre>...</pre>", }; }, }; </script>
条件渲染
React.js
function MyReactComponent() { const [isLoading, setLoading] = useState(true); return ( <div> {isLoading && <span>Loading...</span>} {isLoading ? <div>is loading</div> : <div>is loaded</div>} </div> ); }
Vue.js
<template> <div> <!--v-show: 总是渲染,但根据条件更改CSS--> <span v-show="loading">Loading...</span> <div> <div v-if="loading">is loading</div> <div v-else>is loaded</div> </div> </div> </template> <script> export default { data() { return { loading: true }; }, }; </script>
列表渲染
React.js
function MyReactComponent({ items }) { return ( <ul> {items.map((item) => ( <li key={item.id}> {item.name}: {item.desc} </li> ))} </ul> ); }
Vue.js
<template> <ul> <li v-for="item in items" :key="item.id"> {{item.name}}: {{item.desc}} </li> </ul> </template> <script> export default { props: { items: Array, }, }; </script>
Render-Props
React.js
function Modal({children, isOpen}) { const [isModalOpen, toggleModalOpen] = useState(isOpen); return ( <div className={isModalOpen ? 'open' : 'close'}> {type children === 'function' ? children(toggleModalOpen) : children} </div>) ; } Modal.propTypes = { isOpen: PropTypes.bool, children: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired, } Modal.defaultProps = { isOpen: false, } ... <Modal isOpen> {(toggleModalOpen) => { <div> <div>...</div> <button onClick={() => toggleModalOpen(false)}>Cancel</button> </div> }} </Modal>
Vue.js(slot)
<template> <div v-show="isModalOpen"> <slot v-bind:toggleModal="toggleModalOpen" /> </div> </template> <script> export default { name: "modal", props: { isOpen: { type: Boolean, default: false, }, }, data() { return { isModalOpen: this.isOpen, }; }, methods: { toggleModalOpen(state) { this.isModalOpen = state; }, }, }; </script> ... <Modal isOpen> <template v-slot="slotProps"> <div>...</div> <button @click="slotProps.toggleModal(false)">Close</button> </template> </Modal>
生命周期
React.js
Class component
class MyReactComponent extends React.Component { static getDerivedStateFromProps(props, state) {} componentDidMount() {} shouldComponentUpdate(nextProps, nextState) {} getSnapshotBeforeUpdate(prevProps, prevState) {} componentDidUpdate(prevProps, prevState) {} componentWillUnmount() {} render() { return <div>Hello World</div>; } }
Function component
function MyReactComponent() { // componentDidMount useEffect(() => {}, []); // componentDidUpdate + componentDidMount useEffect(() => {}); // componentWillUnmount useEffect(() => { return () => {...} }, []); // 在渲染之后但在屏幕更新之前同步运行 useLayoutEffect(() => {}, []); return <div>Hello World</div>; }
Vue.js
<template> <div>Hello World</div> </template> <script> export default { beforeCreate() {}, created() {}, beforeMount() {}, mounted() {}, beforeUpdate() {}, updated() {}, beforeDestroy() {}, destroyed() {}, }; </script>
错误处理
React.js
class ErrorBoundary extends React.Component { state = { hasError: false }; static getDerivedStateFromError(error) { // 更新状态,这样下一个渲染将显示回退UI。 return { hasError: true }; } componentDidCatch(error, errorInfo) {} render() { if (this.state.hasError) return <h1>Something went wrong.</h1>; return this.props.children; } } ... <ErrorBoundary> <App /> </ErrorBoundary>
Vue.js
const vm = new Vue({ data: { error: "", }, errorCaptured: function(err, component, details) { error = err.toString(); } }
Ref
React.js
Class component
class AutofocusInput extends React.Component { constructor(props) { super(props); this.ref = React.createRef(); } state = { content: "", }; componentDidMount() { this.ref.current.focus(); } setContent = (e) => { this.setState({ content: e.target.value }); }; render() { return ( <input ref={this.ref} type="text" value={this.state.content} onChange={this.setContent} /> ); } }
Function component
function AutofocusInput() { const [content, setContent] = useState(""); const ref = useRef(null); useEffect(() => { if (ref && ref.current) { ref.current.focus(); } }, []); return ( <input ref={ref} type="text" value={content} onChange={(e) => setContent(e.target.value)} /> ); }
Vue.js
<template> <input ref="input" type="text" v-model="content" /> </template> <script> export default { name: "autofocus-input", data() { return { content: "" }; }, mounted() { this.$refs.input.focus(); }, }; </script>
性能优化
React.js
PureComponent
class MyReactComponent extends React.PureComponent { ... }
shouldComponentUpdate
class MyReactComponent extends React.Component { shouldComponentUpdate(nextProps) {...} ... }
React.memo
export default React.memo( MyReactComponent, (prevProps, nextProps) => { ... } );
useMemo
export default function MyReactComponent() { return React.useMemo(() => { return <div>...</div>; }, []); }
useCallback
function MyItem({ item, handleDelete }) { const handleClick = useCallback(() => handleDelete(item), [ item, handleDelete, ]); return <button onClick={handleClick}>{item.name}</button>; }
Vue.js
v:once
<span v-once>This will never change: {{msg}}</span>
函数式组件:我们可以将组件标记为 functional
,这意味它无状态 (没有响应式数据),也没有实例 (没有 this
上下文)。
<template functional> <h1>Hello {{ name }}</h1> </template> <script> export default { name: "MyVueComponent", props: { name: String, }, }; </script>
keep-alive 组件
<keep-alive> <component :is="view"></component> </keep-alive>
推荐阅读
温故知新 | Vue.js进阶必会,编写你的第一个Vue.js插件
从零开始使用JavaScript制作自己的命令行(CLI工具)
感谢您的阅读和关注,看完三件事:
如果对你有帮助,帮忙文章右下角点个 在看 如果有什么问题欢迎 留言 交流,还可以 转发 ,这是对作者最大的帮助。
Recommend
-
129
You will be redirected to chinese.engadget.com in 9 seconds ... As of November 1st, 2021 Engadget China will...
-
25
IDC报告显示: 2020年第一季度,全球服务器市场的供应商收入为186亿美元,同比下降6.0%; 2020年第一季度,全球服务器出货量为260万台,同比下降0.2%。 其中, 批量服务器收...
-
3
作者 | 苏南 责编 | 欧阳姝黎 出品 | CSDN(ID:CSDNnews)
-
5
世界大学排名:清北并列亚洲第一 力压UCLA 2021年09月02日 11:31 13631 次阅读 稿源:快科技 13 条评论
-
7
沃尔玛应用下载量超过亚马逊!与Shein并列第一!-跨境头条-AMZ123亚马逊导航-跨境电商出海门户 沃尔玛应用下载量超过亚马逊!与Shein并列第一!...
-
3
在编辑博文的时候,有时会想把两张图片并列在一起显示,参考了网上内容,分享一下。 首先记住一点,在markdown里是可以直接写html代码的。这个前提下很自然的有下面的方法: 调整图片宽度/高度: <img src="http://xxx.jpg"...
-
6
怎样一键并列显示双语网页 # 曲径通幽 在浏览网页过程中,翻译外语页面是常见需求。对此,大多数浏览器都提供了内置的翻译功能,可以一键将页面翻译为中文。对此,纯手...
-
5
iPhone 14 Pro Max影像分公布 与 iPhone 14 Pro 并列 ...
-
4
与x86、Arm并列!中国联通加盟RISC-V 2023-03-13 14:02 出处/作者:快科技 整合编辑:佚名 0 近...
-
5
谷歌Pixel 8/Pro DXOMARK屏幕测试总分154 并列榜首 评论(3)...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK