Mathieu Schimmerling b22c36f7db minor fix
2022-04-12 12:50:15 +02:00
2022-04-12 11:18:52 +02:00
2022-04-11 09:58:00 +00:00
2022-04-11 09:56:54 +00:00
2022-04-12 12:50:15 +02:00
2022-04-11 18:20:55 +02:00
2022-04-12 11:27:33 +02:00
2022-04-12 12:50:15 +02:00
2022-04-11 09:56:54 +00:00
2022-04-08 16:18:17 +00:00
2022-04-06 12:29:56 +00:00
2022-04-07 14:04:03 +00:00
2022-04-08 16:18:17 +00:00
2022-04-06 12:29:56 +00:00
2022-04-11 16:08:23 +02:00
2022-04-11 18:20:55 +02:00
2022-04-08 21:43:57 +00:00
2022-03-29 01:25:46 +00:00
2022-04-12 11:18:52 +02:00
2022-04-11 16:35:19 +02:00
2022-04-12 12:50:15 +02:00
2022-04-08 16:18:17 +00:00
2022-04-11 09:56:54 +00:00
2022-04-12 12:50:15 +02:00
2022-04-11 09:56:54 +00:00

Component Party 🎉

Open in Gitpod

Web component JS frameworks quick overview by their syntax and features

Website: https://component-party.pages.dev

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

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

Contributing

This site is built with Astro. Site content is written in Markdown format located in content. For simple edits, you can directly edit the file on GitHub and generate a Pull Request.

For local development, pnpm is preferred as package manager:

pnpm i
pnpm run dev

This project requires Node.js to be v14.0.0 or higher, because we use new JavaScript features in our code, such as optional chaining.


Reactivity

Declare state

Svelte

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

React

import { useState } from 'react';

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

Vue 3

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

Angular

import { Component, Input } from '@angular/core';

@Component({
	selector: 'app-name',
})
export class NameComponent {
	@Input() name: string = 'John';

	constructor() {
		console.log(this.name);
	}
}

Update state

Svelte

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

React

import { useState } from 'react';

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

	console.log(name); // Jane
}

Vue 3

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

Angular

import { Component, Input } from '@angular/core';

@Component({
	selector: 'app-name',
})
export class NameComponent {
	@Input() name: string = 'John';

	constructor() {
		this.name = 'Jane';
		console.log(this.name);
	}
}

Computed state

Svelte

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

React

import { useState, useMemo } from 'react';

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

Vue 3

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

<template>
  <div />
</template>

Angular

import { Component, OnInit, Input, Pipe, PipeTransform, ChangeDetectionStrategy } from '@angular/core';

@Pipe({
	name: 'double',
})
export class DoubleCountPipe implements PipeTransform {
	transform(value: number): number {
		return value * 2;
	}
}

@Component({
	selector: 'app-doublecount',
	template: ' <div></div>',
	changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DoublecountComponent implements OnInit {
	@Input() count: number = 10;

	constructor() {}
}

Templating

Minimal template

Svelte

<h1>Hello world</h1>

React

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

Vue 3

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

Angular

Oops, missing snippet ! You can contribute here to fill this snippet.

Styling

Svelte

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

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

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>
		</>
	);
}

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>

Angular

Oops, missing snippet ! You can contribute here to fill this snippet.

Loop

Svelte

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

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

React

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

Angular

Oops, missing snippet ! You can contribute here to fill this snippet.

Event click

Svelte

<script>
	let count = 0;

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

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

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>
		</>
	);
}

Vue 3

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

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

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

Angular

Oops, missing snippet ! You can contribute here to fill this snippet.

Dom ref

Svelte

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

	let inputElement;

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

<input bind:this={inputElement} />

React

import { useEffect, useRef } from 'react';

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

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

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

Vue 3

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

const inputElement = ref();

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

<template>
  <input ref="inputElement">
</template>

Angular

Oops, missing snippet ! You can contribute here to fill this snippet.

Conditional

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>

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>
		</>
	);
}

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>

Angular

Oops, missing snippet ! You can contribute here to fill this snippet.

Lifecycle

On mount

Svelte

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

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

React

import { useState, useEffect } from 'react';

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

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

	return <p>Page title: {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>

Angular

Oops, missing snippet ! You can contribute here to fill this snippet.

On unmount

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>

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>;
}

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>

Angular

Oops, missing snippet ! You can contribute here to fill this snippet.

Component composition

Props

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>

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,
};

Vue 3

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

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

<template>
  <input v-model="username">
  <UserProfile :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>

Angular

Oops, missing snippet ! You can contribute here to fill this snippet.

Form input

Input text

Svelte

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

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

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} />
		</>
	);
}

Vue 3

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

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

Angular

Oops, missing snippet ! You can contribute here to fill this snippet.

Checkbox

Svelte

<script>
	let isAvailable = false;
</script>

<input id="is-available" type="checkbox" bind:checked={isAvailable} />
<label for="is-available">Is available</label>

React

import { useState } from 'react';

export default function IsAvailable() {
	const [isAvailable, setIsAvailable] = useState(false);

	function handleChange() {
		setIsAvailable(!isAvailable);
	}

	return (
		<>
			<input id="is-available" type="checkbox" checked={isAvailable} onChange={handleChange} />
			<label htmlFor="is-available">Is available</label>
		</>
	);
}

Vue 3

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

const isAvailable = ref(true);
</script>

<template>
  <input
    id="is-available"
    v-model="isAvailable"
    type="checkbox"
  >
  <label for="is-available">Is available</label>
</template>

Angular

Oops, missing snippet ! You can contribute here to fill this snippet.

Radio

Svelte

<script>
	let picked = 'red';
</script>

<div>Picked: {picked}</div>

<input id="blue-pill" bind:group={picked} type="radio" value="blue" />
<label for="blue-pill">Blue pill</label>

<input id="red-pill" bind:group={picked} type="radio" value="red" />
<label for="red-pill">Red pill</label>

React

import { useState } from 'react';

export default function PickPill() {
	const [picked, setPicked] = useState('red');

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

	return (
		<>
			<input id="blue-pill" checked={picked === 'blue'} type="radio" value="blue" onChange={handleChange} />
			<label htmlFor="blue-pill">Blue pill</label>

			<input id="red-pill" checked={picked === 'red'} type="radio" value="red" onChange={handleChange} />
			<label htmlFor="red-pill">Red pill</label>
		</>
	);
}

Vue 3

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

const picked = ref('red');
</script>

<template>
  <div>Picked: {{ picked }}</div>

  <input
    id="blue-pill"
    v-model="picked"
    type="radio"
    value="blue"
  >
  <label for="blue-pill">Blue pill</label>

  <input
    id="red-pill"
    v-model="picked"
    type="radio"
    value="red"
  >
  <label for="red-pill">Red pill</label>
</template>

Angular

Oops, missing snippet ! You can contribute here to fill this snippet.

Select

Svelte

<script>
	let selectedColorId = 2;

	const colors = [
		{ id: 1, text: 'red' },
		{ id: 2, text: 'blue' },
		{ id: 3, text: 'green' },
		{ id: 4, text: 'gray', isDisabled: true },
	];
</script>

<select bind:value={selectedColorId}>
	{#each colors as color}
		<option value={color.id} disabled={color.isDisabled}>
			{color.text}
		</option>
	{/each}
</select>

React

import { useState } from 'react';

const colors = [
	{ id: 1, text: 'red' },
	{ id: 2, text: 'blue' },
	{ id: 3, text: 'green' },
	{ id: 4, text: 'gray', isDisabled: true },
];

export default function ColorSelect() {
	const [selectedColorId, setSelectedColorId] = useState(2);

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

	return (
		<select value={selectedColorId} onChange={handleChange}>
			{colors.map((color) => (
				<option key={color.id} value={color.id} disabled={color.isDisabled}>
					{color.text}
				</option>
			))}
		</select>
	);
}

Vue 3

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

const selectedColorId = ref(2);

const colors = [
	{ id: 1, text: 'red' },
	{ id: 2, text: 'blue' },
	{ id: 3, text: 'green' },
	{ id: 4, text: 'gray', isDisabled: true },
];
</script>

<template>
  <select v-model="selectedColorId">
    <option
      v-for="color in colors"
      :key="color.id"
      :value="color.id"
    >
      {{ color.text }}
    </option>
  </select>
</template>

Angular

Oops, missing snippet ! You can contribute here to fill this snippet.

Webapp features

Routing

Svelte

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

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
    |-- _app.js // global app layout

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

Vue 3

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

Angular

Oops, missing snippet ! You can contribute here to fill this snippet.
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%