Comments 22
Несколько ремарок:
Svelte такого не умеет, или я просто не нашел, как это правильно сделать, поэтому пришлось использовать диспетчер событий
Svelte умеет ровно также:
<button class="square" on:click={() => handleClick(i)}>...</button>
Поэтому диспатчер тут лишний. Он нужен только для создания полностью кастомных событий компонентов. Более того, в вашем случае можно вообще автоматически «всплывать» событие клика на компоненте Square, а не вызывать коллбек. Делается это так:
<button class="square" on:click>...</button>
Далее можно ловить клик прямо на Square и вообще не передавать i в Square:
<Square value={square} on:click={e => handleClick(i)}/>
Заранее извиняюсь, но позволил себе переписать ваш пример немного более рационально.
«0» не поставить, победитель не определяется
const _squares = squares.slice();
_squares[i] = xIsNext ? 'X' : 'O';
squares = _squares;
Подскажите, а в чём суть этого финта с копией массива. Если написать это более простым способом явно поменяв по ключу напрямую — так не сработает?
Попробовал сам так:
squares[i] = xIsNext ? 'X' : 'O';
кажется всё работает.
Понятно. И immer какой-нибудь наверное сюда уже не подключишь, Svelte ведь компилятор :( После стандартных redux-их {… } простыней видеть эти костыли в Svelte, конечно, неприятно.
После стандартных redux-их {… } простыней видеть эти костыли в Svelte, конечно, неприятно.
Так используйте {… } никто также не мешает. Как вы обеспечиваете иммутабильностью Svelte вообще не волнует. Для реактивности важен только факт присвоения значения, а иммутабильность не обязательна и работает внутри. Флагом immutable: true вы лишь говорите Svelte — «тебе не стоит парится на объектами, если ссылка на них не изменилась».
И было бы интересно узнать что из примера выше вы считаете «костялем»? Вроде бы обычный js.
И было бы интересно узнать что из примера выше вы считаете «костялем»?
Очевидно же — две строки из 3-х. Натужная иммутабельность, которая плохо сказывается на читаемости, написании и поддержки кода. Пассаж про обычный js не понял, обычный js не запрещает писать костыли :)
Так используйте {… } никто также не мешает
Гхм… Вы меня наверное недопоняли. От них после redux уже тошно, а вы мне их ещё и в svelte тащить предлагаете? :) Я собственно потому и упомянул immer.
C immer прекрасно работает. Не понимаю какое вообще отношение к этому имеет компиляция.
Ну тут надо пробовать. Я пока близко в Svelte не присматривался. Насколько я понимаю, он выискивает все мутабельные операции и добавляет к ним явные setter-ы. Так что в случае immer тут будет всё зависеть от того, сможет ли он подхватить их, будет ли там callback, как на него отреагирует svelte. Нужно ли будет помещать такой блок в $: {} кодовый блок. Как я и написал выше — надо пробовать и смотреть что получится… Всё таки это компилятор и надо понимать что получится в итоговом js-коде, какие будут обёртки и стоит ли игра свеч.
Очевидно же — две строки из 3-х. Натужная иммутабельность, которая плохо сказывается на читаемости, написании и поддержки кода. Пассаж про обычный js не понял, обычный js не запрещает писать костыли :)
Это же мини-демо проектик. Тащить в него immer или immutablejs для «читаемой» иммутабильности, имхо, было бы лишним. Проще написать 2 дополнительных строчки на чистом js, понятные всем. Пассаж про обычный js был про это.
Гхм… Вы меня наверное недопоняли. От них после redux уже тошно, а вы мне их ещё и в svelte тащить предлагаете? :) Я собственно потому и упомянул immer.
Окей, я понял. Ни разу не являюсь фанатом redux, поэтому ничего не предлагаю. Говорю о том, что можете юзать в Svelte что хотите.
Ну тут надо пробовать. Я пока близко в Svelte не присматривался. Насколько я понимаю, он выискивает все мутабельные операции и добавляет к ним явные setter-ы. Так что в случае immer тут будет всё зависеть от того, сможет ли он подхватить их, будет ли там callback, как на него отреагирует svelte. Нужно ли будет помещать такой блок в $: {} кодовый блок. Как я и написал выше — надо пробовать и смотреть что получится…
Раз не пробовали, тогда поверьте тем, кто пробовали. Юзаем immer на одном проекте. Вот переписал пример с его использованием: REPL
Всё таки это компилятор и надо понимать что получится в итоговом js-коде, какие будут обёртки и стоит ли игра свеч.
Ничего особенного там в этом смысле не получается. Единственное правило — Svelte должен «увидеть» присвоение в стейт. Можно считать что = это автоматический вызов setState. Если подробнее:
// не будет перерисовки, даже если immutable=false
arr.push(item);
// будет перерисовка, если immutable=false
arr.push(item);
arr = arr; // триггер дла set state
// НЕ будет перерисовка, если immutable=true
arr.push(item);
arr = arr;
// будет перерисовка, если immutable=true
arr = [ ...arr, item ];
Последний вариант самый правильный и стоит юзать immutable=true. Как именно вы будете делать иммутабильность для Svelte не важно. В случае с immer:
arr = produce(arr, _arr => _arr.push(item));
// скомпилируется всего лишь в это:
$$invalidate('arr', arr = produce(arr, _arr => _arr.push(item)));
Svelte: reactive declarations
$: winner = calculateWinner(state.squares);
$: status = winner ? `Winner: ${winner}` : `Next player: ${(state.xIsNext ? 'X' : 'O')}`;
//или
$: status = (() => {
const winner = calculateWinner(state.squares);
return winner ? `Winner: ${winner}` : `Next player: ${(state.xIsNext ? 'X' : 'O')}`;
})();
И было бы круто примеры кода сразу в статье видеть. Утомляет каждый раз по ссылке переходить.
$: status = (() => {
const winner = calculateWinner(state.squares);
return winner? `Winner: ${winner}`: `Next player: ${(state.xIsNext? 'X': 'O')}`;
})();
Воу, зачем так сложно)) Это же не JSX какой-то, а обычны JS (по крайней мере синтаксически ;-) ). Можно делать блочные реактивные декларации:
let status;
$: {
const winner = calculateWinner(squares);
status = winner ? `Winner: ${winner}` : `Next player: ${xIsNext ? 'X' : 'O'}`;
}
Но в целом, я бы не стал увлекаться конкатенацией строк в скриптах и полностью перевел бы это дело в шаблон. На случай если вывод статуса нужно будет как-то дополнительно задизайнить, например `Winner: ${winner}` выводить жирным:
<div class="status">
{#if winner}
<b>Winner: {winner}</b>
{:else}
Next player: {xIsNext ? 'X' : 'O'}
{/if}
</div>
Все таки в Svelte у нас html-first и прекрасный DSL для этого.
я бы так делал:
{#if state === 'победа' }
...
{:else if state === 'ничья'}
...
{:else if state === 'ход'}
...
{/if}
<script>
...
$: winner = calculateWinner(squares);
$: draw = ! squares.includes('') && ! winner;
...
</script>
<div class="status">
{#if winner}
Winner: {winner}
{:else if draw}
Draw!
{:else}
Next player: {xIsNext ? 'X' : 'O'}
{/if}
</div>
Обновил мой пример. Тот же draw пригождается еще и для отмены click()
Я, думаю, сделаю новую редакцию статьи и там размещу код. Здесь как, принято ли новую редакцию статьи в виде отдельной статьи оформлять? Если исправить прямо здесь, то новым читателям уже не будут понятны старые комментарии.
Tic Tac Toe, часть 0: Сравнение Svelte и React