Как видите, счетчик в не-fp режиме просто с состоянием . Он хранит состояние так, что может увеличивать или уменьшать его в соответствии с их API.
const createCounter = () => {
let value = 0;
return {
get value() {
return value;
},
increment() {
value = value + 1;
},
decrement() {
value = value - 1;
},
};
};
const counter = createCounter();
console.log('initial value', counter.value);
counter.increment();
counter.increment();
console.log('value after two increments', counter.value);
counter.decrement();
console.log('value after one decrement', counter.value);
Функциональным способом построения счетчика является , позволяющий потребителю предоставить состояние . Функции знают только, как изменить его:
const incrementCounter = counter => counter + 1;
const decrementCounter = counter => counter - 1;
const value = 0;
console.log('initial value', value);
const valueAfterTwoIncrements = incrementCounter(
incrementCounter(value),
);
console.log('value after two increments', valueAfterTwoIncrements);
const valueAfterOneDecrement = decrementCounter(valueAfterTwoIncrements);
console.log('value after one decrement', valueAfterOneDecrement);
Преимущества этого подхода почти неисчислимы, функции чисты и их выходной детерминирован, поэтому тестирование очень простое и т. Д.
Вопросы и ответы:
- «Позвольте потребителю предоставить состояние»: функции (inc / dec) не работают с собственным состоянием, они принимают его в качестве аргумента и возвращают его новую версию. Попробуйте представить себе редукторный редуктор , они только встраивают логику для изменения состояния ... но в конечном итоге состояние передается в качестве аргумента.
- ", где значения продолжают увеличиваться/ decmented ": состояние никогда не меняется, это называется immutability , чистые функции всегда будут возвращать новую его копию, так что если вы захотите, вы должны сохранить ее где-то еще.
Работа с DOM
Отдельный уровень представления от фактического уровня бизнес-логики
Как видно из следующегоНапример, представление не осведомлено о данных, dom используется только для визуализации или запуска событий пользовательского интерфейса, в то время как фактическая бизнес-логика (текущее значение состояния и порядок включения / удаления) хранится на другом и хорошо разделенном слое. Слой оркестровки в конечном итоге используется для связывания этих двух слоев.
/***** View Layer *****/
const IncBtn = ({ dispatch }) => {
dispatch({ type: 'INC' });
};
const DecBtn = ({ dispatch }) => {
dispatch({ type: 'DEC' });
};
const Value = ({ getState }) => {
document.querySelector('#value').value = getState();
};
/***** Business Logic Layer *****/
const counter = (state = 0, { type }) => {
switch(type) {
case 'INC':
return state + 1;
case 'DEC':
return state - 1;
default:
return state;
}
};
/***** Orchestration Layer *****/
const createStore = (reducer) => {
let state = reducer(undefined, { type: 'INIT' });
return {
dispatch: (action) => {
state = reducer(state, action);
},
getState: () => state,
};
}
(() => {
const store = createStore(counter);
// first render
Value(store);
document
.querySelector('#inc')
.addEventListener('click', () => {
IncBtn(store);
Value(store);
});
document
.querySelector('#dec')
.addEventListener('click', () => {
DecBtn(store);
Value(store);
});
})();
<button id="inc">Increment</button>
<button id="dec">Decrement</button>
<hr />
<input id="value" readonly disabled/>