https://xstate.js.org/docs/guides/context.html#initial-context
import { createMachine, assign } from 'xstate';
// Action to increment the context amount
const addWater = assign({
amount: (context, event) => context.amount + 1
});
// Guard to check if the glass is full
function glassIsFull(context, event) {
return context.amount >= 10;
}
const glassMachine = createMachine(
{
id: 'glass',
// the initial context (extended state) of the statechart
context: {
amount: 0
},
initial: 'empty',
states: {
empty: {
on: {
FILL: {
target: 'filling',
actions: 'addWater'
}
}
},
filling: {
// Transient transition
always: {
target: 'full',
cond: 'glassIsFull'
},
on: {
FILL: {
target: 'filling',
actions: 'addWater'
}
}
},
full: {}
}
},
{
actions: { addWater },
guards: { glassIsFull }
}
);
const nextState = glassMachine.transition(glassMachine.initialState, {
type: 'FILL'
});
nextState.context;
// => { amount: 1 }
Initial Context (์ด๊ธฐ ์ปจํ ์คํธ)
const counterMachine = createMachine({
id: 'counter',
// initial context
context: {
count: 0,
message: 'Currently empty',
user: {
name: 'David'
},
allowedToIncrement: true
// ... etc.
},
states: {
// ...
}
});
๋์ ์ปจํ ์คํธ(์ฆ, ์ด๊ธฐ ๊ฐ์ด ์ธ๋ถ์์ ์ ๊ณต๋๋ ์ปจํ ์คํธ)์ ๊ฒฝ์ฐ ,
์ ๊ณต๋ ์ปจํ ์คํธ ๊ฐ์ผ๋ก ๋จธ์ ์ ์์ฑํ๋ ๋จธ์ ํฉํ ๋ฆฌ ํจ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค(๊ตฌํ์ ๋ค๋ฅผ ์ ์์).
const createCounterMachine = (count, time) => {
return createMachine({
id: 'counter',
// values provided from function arguments
context: {
count,
time
}
// ...
});
};
const counterMachine = createCounterMachine(42, Date.now());
const counterMachine = createMachine({
/* ... */
});
// retrieved dynamically
const someContext = { count: 42, time: Date.now() };
const dynamicCounterMachine = counterMachine.withContext(someContext);
dynamicCounterMachine.initialState.context;
// => { count: 42, time: 1543687816981 }
์ด๊ฒ์ ์ด๊ธฐ ์ํ๊ฐ ์ด๊ธฐ assign(...) ์์ ๊ณผ ์ผ์์ ์ธ ์ ํ(์๋ ๊ฒฝ์ฐ)์ ํตํด ๊ณ์ฐ๋๊ธฐ ๋๋ฌธ์,
machine.context์ ์ง์ ์ก์ธ์คํ๋ ๊ฒ๋ณด๋ค ์ ํธ๋ฉ๋๋ค.
Assign Action (ํ ๋น ์ก์ )
Argument | Type | Description |
assigner | object or function | The object assigner or function assigner which assigns values to the context (see below) |
import { createMachine, assign } from 'xstate';
// example: property assigner
// ...
actions: assign({
// increment the current count by the event value
count: (context, event) => context.count + event.value,
// assign static value to the message (no function needed)
message: 'Count changed'
}),
// ...
// example: context assigner
// ...
// return a partial (or full) updated context
actions: assign((context, event) => {
return {
count: context.count + event.value,
message: 'Count changed'
}
}),
// ...
Argument | Type | Description |
context | TContext | The current context (extended state) of the machine |
event | EventObject | The event that triggered the assign action |
meta 4.7+ | AssignMeta | an object with meta data (see below) |
- state - ์ผ๋ฐ ์ ํ์ ํ์ฌ ์ํ(์ด๊ธฐ ์ํ ์ ํ์ ๋ํด ์ ์๋์ง ์์)
- action - assign action
๊ฒฝ๊ณ
assign(...) ํจ์๋ ์์ ์์ฑ์์ ๋๋ค. ์ก์ ๊ฐ์ฒด๋ง ๋ฐํํ๊ณ ์ปจํ ์คํธ์ ๋ช ๋ น์ ์ผ๋ก ํ ๋นํ์ง ์๋ ์์ ํจ์์ ๋๋ค
Action Order
const counterMachine = createMachine({
preserveActionOrder: true, // Ensures that assign actions are called in order
// ...
context: { count: 0 },
states: {
active: {
on: {
INC_TWICE: {
actions: [
(context) => console.log(`Before: ${context.count}`), // "Before: 0"
assign({ count: (context) => context.count + 1 }), // count === 1
assign({ count: (context) => context.count + 1 }), // count === 2
(context) => console.log(`After: ${context.count}`) // "After: 2"
]
}
}
}
}
});
interpret(counterMachine).start().send({ type: 'INC_TWICE' });
// => "Before: 0"
// => "After: 2"
const counterMachine = createMachine({
id: 'counter',
context: { count: 0 },
initial: 'active',
states: {
active: {
on: {
INC_TWICE: {
actions: [
(context) => console.log(`Before: ${context.count}`), // "Before: 2"
assign({ count: (context) => context.count + 1 }), // count === 1
assign({ count: (context) => context.count + 1 }), // count === 2
(context) => console.log(`After: ${context.count}`) // "After: 2"
]
}
}
}
}
});
interpret(counterMachine).start().send({ type: 'INC_TWICE' });
// => "Before: 2"
// => "After: 2"
์ด๋ ๋ assign(...) ์ก์ ์ด ์์๋๋ก ๋ฐฐ์น๋๊ณ , ๋จผ์ (๋ง์ดํฌ๋ก์คํ ์์) ์คํ๋๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋ฐ๋ผ์ ๋ค์ ์ํ ์ปจํ ์คํธ๋ { count: 2 }์ด๋ฉฐ ๋๋จธ์ง ๋ ์ฌ์ฉ์ ์ง์ ์์ ์ ๋ชจ๋ ์ ๋ฌ๋ฉ๋๋ค.
์ด ์ ํ์ ๋ํด ์๊ฐํ๋ ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ด ์ฝ๋ ๊ฒ์ ๋๋ค.
ํ์ฑ ์ํ์์ INC_TWICE ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ๋ค์ ์ํ๋ context.count๊ฐ ์ ๋ฐ์ดํธ๋ ํ์ฑ ์ํ์ด๋ฉฐ,
์ด๋ฌํ ์ฌ์ฉ์ ์ง์ ์์ ์ ํด๋น ์ํ์์ ์คํ๋ฉ๋๋ค.
const counterMachine = createMachine({
id: 'counter',
context: { count: 0, prevCount: undefined },
initial: 'active',
states: {
active: {
on: {
INC_TWICE: {
actions: [
(context) => console.log(`Before: ${context.prevCount}`),
assign({
count: (context) => context.count + 1,
prevCount: (context) => context.count
}), // count === 1, prevCount === 0
assign({ count: (context) => context.count + 1 }), // count === 2
(context) => console.log(`After: ${context.count}`)
]
}
}
}
}
});
interpret(counterMachine).start().send({ type: 'INC_TWICE' });
// => "Before: 0"
// => "After: 2"
- ํ์ฅ ์ํ(์ปจํ ์คํธ)๋ ๋ณด๋ค ๋ช ์์ ์ผ๋ก ๋ชจ๋ธ๋ง๋ฉ๋๋ค.
- ์์์ ์ค๊ฐ ์ํ๊ฐ ์์ผ๋ฏ๋ก ์ก๊ธฐ ์ด๋ ค์ด ๋ฒ๊ทธ๋ฅผ ๋ฐฉ์งํฉ๋๋ค.
- ์์ ์์๋ ๋ ๋ ๋ฆฝ์ ์ ๋๋ค("์ด์ " ๋ก๊ทธ๋ "์ดํ" ๋ก๊ทธ ๋ค์ ์ฌ ์๋ ์์ต๋๋ค!)
- ์ํ ํ ์คํธ ๋ฐ ๊ฒ์ฌ ์ด์ง
Notes (์ฃผ๋ชฉ)
- ๐ซ ๊ธฐ๊ณ์ ์ปจํ ์คํธ๋ฅผ ์ธ๋ถ์์ ๋ณ๊ฒฝํ์ง ๋ง์ญ์์ค. ๋ชจ๋ ๊ฒ์ ์ด์ ๊ฐ ์๊ณ ๋ชจ๋ ์ปจํ ์คํธ ๋ณ๊ฒฝ์ ์ด๋ฒคํธ๋ก ์ธํด ๋ช ์์ ์ผ๋ก ๋ฐ์ํด์ผ ํฉ๋๋ค.
- assign({ ... })์ ๊ฐ์ฒด ๊ตฌ๋ฌธ์ ์ ํธํฉ๋๋ค. ์ด๋ฅผ ํตํด ํฅํ ๋ถ์ ๋๊ตฌ์์ ํน์ ์์ฑ์ด ์ ์ธ์ ์ผ๋ก ์ด๋ป๊ฒ ๋ณ๊ฒฝ๋ ์ ์๋์ง ์์ธกํ ์ ์์ต๋๋ค.
- ํ ๋น์ ๋์ ๋ ์ ์์ผ๋ฉฐ ์์ฐจ์ ์ผ๋ก ์คํ๋ฉ๋๋ค.
// ...
actions: [
assign({ count: 3 }), // context.count === 3
assign({ count: context => context.count * 2 }) // context.count === 6
],
// ...
- ์ก์ ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก assign() ์ก์ ์ ๋ฌธ์์ด์ด๋ ํจ์๋ก ํํํ ๋ค์ ๋จธ์ ์ต์ ์์ ์ฐธ์กฐํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ต๋๋ค.
const countMachine = createMachine({
initial: 'start',
context: { count: 0 }
states: {
start: {
entry: 'increment'
}
}
}, {
actions: {
increment: assign({ count: context => context.count + 1 }),
decrement: assign({ count: context => context.count - 1 })
}
});
- ๋๋ ๋ช ๋ช ๋ ํจ์๋ก ๋ง์ ๋๋ค. (์์ ๋์ผํ ๊ฒฐ๊ณผ):
const increment = assign({ count: context => context.count + 1 });
const decrement = assign({ count: context => context.count - 1 });
const countMachine = createMachine({
initial: 'start',
context: { count: 0 }
states: {
start: {
// Named function
entry: increment
}
}
});
- ์ด์์ ์ผ๋ก ์ปจํ ์คํธ๋ ์ผ๋ฐ JavaScript ๊ฐ์ฒด๋ก ํํํ ์ ์์ด์ผ ํฉ๋๋ค. ์ฆ, JSON์ผ๋ก ์ง๋ ฌํํ ์ ์์ด์ผ ํฉ๋๋ค.
- assign() ์ก์
์ด ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ์ก์
์ด ์คํ๋๊ธฐ ์ ์ ์ปจํ
์คํธ๊ฐ ์
๋ฐ์ดํธ๋ฉ๋๋ค.
- ์ด๋ ๋์ผํ ๋จ๊ณ ๋ด์ ๋ค๋ฅธ ์ก์ ์ด assign() ์ก์ ์ด ์คํ๋๊ธฐ ์ ์ ์ปจํ ์คํธ๊ฐ ์๋ ์ ๋ฐ์ดํธ๋ ์ปจํ ์คํธ๋ฅผ ๊ฐ์ ธ์ด์ ์๋ฏธํฉ๋๋ค.
- ๋น์ ์ ์ํ๋ ์ก์ ์ ์์์ ์์กดํด์๋ ์ ๋์ง๋ง, ์ด๋ฅผ ์ผ๋์ ๋์ญ์์ค(์ถํ ๋ณ๊ฒฝ ๊ฐ๋ฅ). ์์ธํ ๋ด์ฉ์ action order๋ฅผ ์ฐธ์กฐํ์ธ์.
ํ์ ์คํฌ๋ฆฝํธ (์คํค๋ง)
์ ์ ํ ํ์ ์ ์ถ๋ฅผ ์ํด ์ปจํ ์คํธ ํ์ ์ ์์คํ ์ ์คํค๋ง ์์ฑ์ ์ถ๊ฐํฉ๋๋ค.
import { createMachine } from 'xstate';
interface CounterContext {
count: number;
user?: {
name: string;
};
}
const machine = createMachine({
schema: {
context: {} as CounterContext
},
// ...
context: {
count: 0,
user: undefined
}
// ...
});
typeof ...๋ฅผ ์ฝ์ด๋ก ์ฌ์ฉํ ์๋ ์์ต๋๋ค.
const context = {
count: 0,
user: { name: '' }
};
const machine = createMachine({
schema: {
context: {} as typeof context
},
// ...
context
// ...
});โ
// ...
on: {
INCREMENT: {
// Generics guarantee proper inference
actions: assign<CounterContext, CounterEvent>({
count: (context) => {
// context: { count: number }
return context.count + 1;
}
});
}
}
// ...
Quick Reference
์ด๊ธฐ ์ปจํ ์คํธ ์ธํ
const machine = createMachine({
// ...
context: {
count: 0,
user: undefined
// ...
}
});
๋์ ์ด๊ธฐ ์ปจํ ์คํธ ์ธํ (๋จธ์ ํฉํฐ๋ฆฌ)
const createSomeMachine = (count, user) => {
return createMachine({
// ...
// Provided from arguments; your implementation may vary
context: {
count,
user
// ...
}
});
};
๋์ ์ด๊ธฐ ์ปจํ ์คํธ ์ธํ (withContext)
const machine = createMachine({
// ...
// Provided from arguments; your implementation may vary
context: {
count: 0,
user: undefined
// ...
}
});
const myMachine = machine.withContext({
count: 10,
user: {
name: 'David'
}
});
์ปจํ ์คํธ์ ํ ๋น
const machine = createMachine({
// ...
context: {
count: 0,
user: undefined
// ...
},
// ...
on: {
INCREMENT: {
actions: assign({
count: (context, event) => context.count + 1
})
}
}
});
ํ ๋น (์ ์ ํ ๋น - ์์ฑ ๋ณ)
// ...
actions: assign({
counter: 42
}),
// ...
ํ ๋น (์์ฑ ๋ณ ํ ๋น)
// ...
actions: assign({
counter: (context, event) => {
return context.count + event.value;
}
}),
// ...
ํ ๋น (์ปจํ ์คํธ ํต์งธ๋ก)
// ...
actions: assign((context, event) => {
return {
counter: context.count + event.value,
time: event.time,
// ...
}
}),
// ...
์ฌ๋ฌ๋ฒ ํ ๋นํ๊ธฐ
// ...
// assume context.count === 1
actions: [
// assigns context.count to 1 + 1 = 2
assign({ count: (context) => context.count + 1 }),
// assigns context.count to 2 * 3 = 6
assign({ count: (context) => context.count * 3 })
],
// ...
'FrontEnd' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
XState : ํ์ ์คํฌ๋ฆฝํธ์ ๊ฐ์ด ํ์ฉํ๊ธฐ (0) | 2022.05.05 |
---|---|
XState : ์ปจํ ์คํธ์ ์ด๋ฒคํธ ๋ชจ๋ธ๋ง (0) | 2022.05.05 |
XState์ Effect(๋ถ์ ํจ๊ณผ) - Action (0) | 2022.05.04 |
XState์ Actor ์์๋ณด๊ธฐ (0) | 2022.05.04 |
XState ๊ณต์ ๋ฌธ์ ๋ฒ์ญ : ์๋น์ค ํธ์ถ(Invoking Services) (0) | 2022.05.01 |