React uses JSX to define markup directly in JavaScript:
// Component.jsx
export default function Component({ greeting }) {
return <p>{greeting}</p>;
}
<!-- Component.vue -->
<script setup>
const props = defineProps(['greeting']);
</script>
<template>
<p>{{ greeting }}</p>
</template>
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(json => {
setData(json);
setLoading(false);
});
}, [url]);
return { data, loading };
}
import { ref, onMounted } from 'vue';
function useFetch(url) {
const data = ref(null);
const loading = ref(true);
onMounted(async () => {
const response = await fetch(url);
data.value = await response.json();
loading.value = false;
});
return { data, loading };
}
React pattern:
<ChildComponent onDataChange={handleDataChange} />
<ChildComponent @data-change="handleDataChange" />
function ChildComponent({ onDataChange }) {
return <button onClick={() => onDataChange('New Data')}>Click</button>;
}
<script setup>
const emit = defineEmits(['data-change']);
function changeData() {
emit('data-change', 'New Data');
}
</script>
<template>
<button @click="changeData">Click</button>
</template>
React:
<ChildComponent>
<h1>Hello</h1>
</ChildComponent>
<ChildComponent>
<template #default>
<h1>Hello</h1>
</template>
</ChildComponent>
<template>
<slot name="header"></slot>
<slot></slot> <!-- default -->
<slot name="footer"></slot>
</template>
React:
<MouseTracker render={({ x, y }) => <p>{x}, {y}</p>} />
<MouseTracker v-slot="{ position }">
<p>{{ position.x }}, {{ position.y }}</p>
</MouseTracker>
React:
<ThemeContext.Provider value={{ theme, setTheme }}>
<App />
</ThemeContext.Provider>
<script setup>
const theme = ref('light');
provide('theme', theme);
</script>
<script setup>
const theme = inject('theme');
</script>
React pattern using as prop:
function Box({ as: Component = 'div', ...props }) {
return <Component {...props} />;
}
<component :is="as"></component>