Mathieu Schimmerling 3c342f2ebc add gitpod support
2022-04-06 11:44:35 +00:00
2022-04-06 11:29:07 +00:00
2022-03-29 00:30:30 +00:00
2022-04-06 11:44:35 +00:00
2022-04-06 11:29:07 +00:00
2022-04-06 10:58:19 +00:00
2022-03-29 01:13:13 +00:00
2022-04-06 11:44:35 +00:00
2022-03-29 00:30:30 +00:00
2022-04-06 10:58:19 +00:00
2022-04-06 10:58:19 +00:00
2022-03-29 01:25:46 +00:00
2022-04-03 14:38:45 +00:00
2022-04-03 14:38:45 +00:00
2022-04-06 11:44:35 +00:00
2022-04-06 11:44:35 +00:00

Component Party

Open in Gitpod

Web component JS frameworks quick overview by their syntax and features

Why ?

Many JS developers don't have a good overview of every existing JS framework with their own syntax and features. How do we solve this ? Developers love having framework overview by examples. It's a quick introduction before going deeper.

Roadmap

  • Website (built with Astro)
  • Add SolidJS support
  • Add Angular support
  • Add Preact support
  • Add Alpine support
  • Add React support
  • Add Svelte support
  • Add Vue 3 support

Contributing

  1. Fork it!
  2. Create your feature branch: git checkout -b my-new-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request :D

Documentation

Reactivity

Declare state

React

import { useState } from 'react';

export default function Name() {
	const [name] = useState("John");
	console.log(name);
}

Svelte

<script>
	let name = 'John';
	console.log(name);
</script>

Vue 3

<script setup>
import { ref } from 'vue';
const name = ref('John');
console.log(name.value);
</script>

Update state

React

import { useState } from 'react';

export default function Name() {
	const [name, setName] = useState("John");
	setName('Jane');

	console.log(name);
}

Svelte

<script>
	let name = 'John';
	name = 'Jane';
	console.log(name);
</script>

Vue 3

<script setup>
import { ref } from 'vue';
const name = ref('John');
name.value = 'Jane';
console.log(name.value);
</script>

Computed state

React

import { useState, useMemo } from 'react';

export default function DoubleCount() {
	const [count] = useState(0);
	const doubleCount = useMemo(() => count * 2, [count]);
	console.log(doubleCount);
	return <div />;
}

Svelte

<script>
	let count = 10;
	$: doubleCount = count * 2;
	console.log(doubleCount);
</script>

Vue 3

<script setup>
import { ref, computed } from 'vue';
const count = ref(10);
const doubleCount = computed(() => count.value * 2);
console.log(doubleCount.value);
</script>

<template>
  <div />
</template>

Watch state

Templating

Minimal template

React

export default function HelloWorld() {
	return <h1>Hello world</h1>;
}

Svelte

<h1>Hello world</h1>

Vue 3

<template>
  <h1>Hello world</h1>
</template>

Styling

React

export default function HelloWorld() {
	// how do you declare title class ??

	return (
		<>
			<h1 className="title">Hello world</h1>
			<button style={{ 'font-size': '10rem' }}>I am a button</button>
		</>
	);
}

Svelte

<template>
	<h1 class="title">Hello world</h1>
	<button style="font-size: 10rem;">I am a button</button>
</template>

<style>
	.title {
		color: red;
	}
</style>

Vue 3

<template>
  <h1 class="title">
    Hello world
  </h1>
  <button style="font-size: 10rem">
    I am a button
  </button>
</template>

<style scoped>
.title {
	color: red;
}
</style>

Loop

React

export default function Colors() {
	const colors = ['red', 'green', 'blue'];
	return (
		<ul>
			{colors.map((color) => (
				<li key={color}>{color}</li>
			))}
		</ul>
	);
}

Svelte

<script>
	const colors = ['red', 'green', 'blue'];
</script>

<ul>
	{#each colors as color}
		<li>{color}</li>
	{/each}
</ul>

Vue 3

<script setup>
const colors = ['red', 'green', 'blue'];
</script>

<template>
  <ul>
    <li
      v-for="color in colors"
      :key="color"
    >
      {{ color }}
    </li>
  </ul>
</template>

Event click

React

import { useState } from 'react';

export default function Name() {
	const [count, setCount] = useState(0);

	function incrementCount() {
		setCount(count + 1);
	}

	return (
		<>
			<p>Counter: {count}</p>
			<button onClick={incrementCount}>+1</button>
		</>
	);
}

Svelte

<script>
	let count = 0;

	function incrementCount() {
		count += 1;
	}
</script>

<p>Counter: {count}</p>
<button on:click={incrementCount}>+1</button>

Vue 3

<script setup>
import { ref } from 'vue';
const count = ref(0);

function incrementCount() {
	count.value = count.value + 1;
}
</script>

<template>
  <p>Counter: {{ count }}</p>
  <button @click="incrementCount">
    +1
  </button>
</template>

Dom ref

React

import { useEffect, useRef } from 'react';

export default function InputFocused() {
	const inputElement = useRef(null);

	useEffect(() => inputElement.current.focus())

	return <input type="text" ref={inputElement} />;
}

Svelte

<script>
	import { onMount } from 'svelte';

	let inputElement;

	onMount(() => {
		inputElement.focus();
	});
</script>

<input bind:this={inputElement} />

Vue 3

<script setup>
import { ref, onMounted } from 'vue';

const inputElement = ref();

onMounted(() => {
	inputElement.value.focus();
});
</script>

<input ref="inputElement" />

Conditional

React

import { useState, useMemo } from 'react';

const TRAFFIC_LIGHTS = ['red', 'orange', 'green'];

export default function TrafficLight() {
	const [lightIndex, setLightIndex] = useState(0);

	const light = useMemo(() => TRAFFIC_LIGHTS[lightIndex], [lightIndex]);

	function nextLight() {
		if (lightIndex + 1 > TRAFFIC_LIGHTS.length - 1) {
			setLightIndex(0);
		} else {
			setLightIndex(lightIndex + 1);
		}
	}

	return (
		<>
			<button onClick={nextLight}>Next light</button>
			<p>Light is: {light}</p>
			<p>
				You must
				{light === 'red' && <span>STOP</span>}
				{light === 'orange' && <span>SLOW DOWN</span>}
				{light === 'green' && <span>GO</span>}
			</p>
		</>
	);
}

Svelte

<script>
	const TRAFFIC_LIGHTS = ['red', 'orange', 'green'];
	let lightIndex = 0;

	$: light = TRAFFIC_LIGHTS[lightIndex];

	function nextLight() {
		if (lightIndex + 1 > TRAFFIC_LIGHTS.length - 1) {
			lightIndex = 0;
		} else {
			lightIndex++;
		}
	}
</script>

<button on:click={nextLight}>Next light</button>
<p>Light is: {light}</p>
<p>
	You must
	{#if light === 'red'}
		STOP
	{:else if light === 'orange'}
		SLOW DOWN
	{:else if light === 'green'}
		GO
	{/if}
</p>

Vue 3

<script setup>
import { ref, computed } from 'vue';
const TRAFFIC_LIGHTS = ['red', 'orange', 'green'];
const lightIndex = ref(0);

const light = computed(() => TRAFFIC_LIGHTS[lightIndex]);

function nextLight() {
	if (lightIndex.value + 1 > TRAFFIC_LIGHTS.length - 1) {
		lightIndex.value = 0;
	} else {
		lightIndex.value++;
	}
}
</script>

<template>
  <button @click="nextLight">
    Next light
  </button>
  <p>Light is: {{ light }}</p>
  <p>
    You must
    <span v-if="light === 'red'">STOP</span>
    <span v-else-if="light === 'orange'">SLOW DOWN</span>
    <span v-else-if="light === 'green'">GO</span>
  </p>
</template>

Lifecycle

On mount

React

import { useState, useEffect } from 'react';

export default function PageTitle() {
	const [pageTitle, setPageTitle] = useState('');

	useEffect(() => {
		setPageTitle(document.title);
	});

	return <p>Page title: {pageTitle}</p>;
}

Svelte

<script>
	import { onMount } from 'svelte';
	let pageTitle = '';
	onMount(() => {
		pageTitle = document.title;
	});
</script>

<p>Page title is: {pageTitle}</p>

Vue 3

<script setup>
import { ref, onMounted } from 'vue';
const pageTitle = ref('');
onMounted(() => {
	pageTitle.value = document.title;
});
</script>

<template>
  <p>Page title: {{ pageTitle }}</p>
</template>

On unmount

React

import { useState, useEffect } from 'react';

export default function Time() {
	const [time, setTime] = useState(new Date().toLocaleTimeString());

	const timer = setInterval(() => {
		setTime(new Date().toLocaleTimeString());
	}, 1000);

	useEffect(() => {
		return () => {
			clearInterval(timer);
		};
	});

	return <p>Current time: {time}</p>;
}

Svelte

<script>
	import { onDestroy } from 'svelte';

	let time = new Date().toLocaleTimeString();

	const timer = setInterval(() => {
		time = new Date().toLocaleTimeString();
	}, 1000);

	onDestroy(() => {
		clearInterval(timer);
	});
</script>

<p>Current time: {time}</p>

Vue 3

<script setup>
import { ref, onUnmounted } from 'vue';

const time = ref(new Date().toLocaleTimeString());

const timer = setInterval(() => {
	time.value = new Date().toLocaleTimeString();
}, 1000);

onUnmounted(() => {
	clearInterval(timer);
});
</script>

<p>Current time: {time}</p>

Component composition

Props

React

import UserProfile from './UserProfile.jsx';

export default function App() {
	return <UserProfile name="John" age={20} favouriteColors={['green', 'blue', 'red']} isAvailable />;
}

import PropTypes from 'prop-types';

export default function UserProfile({ name = '', age = null, favouriteColors = [], isAvailable = false }) {
	return (
		<>
			<p>My name is {name} !</p>
			<p>My age is {age} !</p>
			<p>My favourite colors are {favouriteColors.split(', ')} !</p>
			<p>I am {isAvailable ? 'available' : 'not available'}</p>
		</>
	);
}

UserProfile.propTypes = {
	name: PropTypes.string.isRequired,
	age: PropTypes.number.isRequired,
	favouriteColors: PropTypes.arrayOf(PropTypes.string).isRequired,
	isAvailable: PropTypes.bool.isRequired
};

Svelte

<script>
	import UserProfile from './UserProfile.svelte';
</script>

<UserProfile name="John" age={20} favouriteColors={['green', 'blue', 'red']} isAvailable />

<script>
	export let name = ""
	export let age = null
	export let favouriteColors = []
	export let isAvailable = false
</script>

<p>My name is {name} !</p>
<p>My age is {age} !</p>
<p>My favourite colors are {favouriteColors.split(', ')} !</p>
<p>I am {isAvailable ? 'available' : 'not available'}</p>

Vue 3

<script setup>
import { ref } from 'vue';
import Hello from './UserProfile.vue';

const username = ref('John');
</script>

<template>
  <input v-model="username">
  <Hello :name="username" />
</template>

<script setup>
const props = defineProps({
	name: {
		type: String,
		required: true,
		default: ""
	},
	age: {
		type: Number,
		required: true,
		default: null
	},
	favouriteColors: {
		type: Array,
		required: true,
		default: () => []
	},
	isAvailable: {
		type: Boolean,
		required: true,
		default: false
	}
});
</script>

<template>
  <p>My name is {{ props.name }} !</p>
  <p>My age is {{ props.age }} !</p>
  <p>My favourite colors are {{ props.favouriteColors.split(', ') }} !</p>
  <p>I am {{ props.isAvailable ? 'available' : 'not available' }}</p>
</template>

Event custom

Slot

Slot named

Slot props

Event dom forwarding

Store context

Form input

Input binding

React

import { useState } from 'react';

export default function InputHello() {
	const [text, setText] = useState('Hello world');

	function handleChange(event) {
		setText(event.target.value);
	}

	return (
		<>
			<p>{text}</p>
			<input value={text} onChange={handleChange} />
		</>
	);
}

Svelte

<script>
	let text = 'Hello World';
</script>

<p>{text}</p>
<input bind:value={text} />

Vue 3

<script setup>
import { ref } from 'vue';
const text = ref('Hello World');
</script>

<template>
  <p>{{ text }}</p>
  <input v-model="text">
</template>

Webapp features

Routing

React

|-- pages/
    |-- index.js // index page "/"
    |-- about.js // about page "/about"
    |-- 404.js // handle error HTTP 404 page not found
    |-- 500.js // handle error HTTP 500

https://remix.run/docs/en/v1/guides/routing

Svelte

|-- routes/
    |-- index.svelte // index page "/"
    |-- about.svelte // about page "/about"
    |-- __error.svelte // handle HTTP errors 404, 500,...
    |-- __layout.svelte // global app layout

Vue 3

|-- pages/
    |-- index.vue // index page "/"
    |-- about.vue // about page "/about"

Layouts

Ssr

Real usecase

Showcases

Todolist

Fetch

Description
component-party的中文版本
Readme MIT 4.1 MiB
Languages
TypeScript 50.7%
JavaScript 18.6%
Svelte 14%
HTML 7.5%
Vue 5%
Other 4.2%