React.js和Vue.js的語法並列比較

React.js和Vue.js都是很好的框架。並且Next.js和Nuxt.js甚至將它們帶入了一個新的高度,這有助於咱們以更少的配置和更好的可維護性來建立應用程序。可是,若是你必須常常在框架之間切換,在深刻探討另外一個框架以後,你可能會輕易忘記另外一個框架中的語法。在本文中,我總結了這些框架的基本語法和方案,而後並排列出。我但願這能夠幫助咱們儘快掌握語法,不過限於篇幅,這篇文章只比較React.js和Vue.js,下一篇再談Next.js個Nuxt.js。javascript

Github:github.com/oahehc/reac…html

Render

React.js前端

ReactDOM.render(<App />, document.getElementById("root")); 複製代碼

Vue.jsvue

new Vue({
  render: (h) => h(App),
}).$mount("#root");
複製代碼

基本組件

React.js

Class componentjava

class MyReactComponent extends React.Component {
  render() {
    return <h1>Hello world</h1>;
  }
}
複製代碼

Function componentreact

function MyReactComponent() {
  return <h1>Hello world</h1>;
}
複製代碼

Vue.js

<template>
  <h1>Hello World</h1>
</template>
<script> export default { name: "MyVueComponent", }; </script>
複製代碼

Prop

React.jsgit

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.jsgithub

<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 componentapi

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>
複製代碼

完。


本文首發於公衆號 《前端全棧開發者》 ID:by-zhangbing-dev,第一時間閱讀最新文章,會優先兩天發表新文章。關注後私信回覆:大禮包,送某網精品視頻課程網盤資料,準能爲你節省很多錢!

相關文章
相關標籤/搜索