Czesc, stosujecie dekoratory w aplikacjach reactowych ?
Co masz na myśli pisząc dekoratory? Jeśli ci chodzi o wzorzec projektowy dekoratora https://pl.wikipedia.org/wiki/Dekorator_(wzorzec_projektowy) to owszem, zdarza mi się pisać Higher Order Components, np.
function foo(Component) {
return () => <Component foo="x" />
}
czyli w zasadzie funkcja foo jest takim dekoratorem (jeśli rozumieć dekorator jako wzorzec projektowy).
Jednak NIE korzystam z dekoratorów jako część języka (czyli nie korzystam z tej nowości @costam
, tylko samemu opakowuję to w odpowiednie funkcje. Nie mam nic przeciwko notacji z małpą, po prostu nie dotarłem do tego jeszcze, nie wiem czy w ogóle jest to już w języku, z tej tablicy wynika, że nie ma wsparcia nigdzie dla tego: http://kangax.github.io/compat-table/esnext/ ).
Natywnego nie ma, ale po to sa transpilatory :)
Problem w tym, że dekoratory nie weszły jeszcze do języka (z tego co widzę, to są na stage 2 dopiero, czyli draft https://github.com/tc39/proposal-decorators )
lista stage'ów: https://tc39.github.io/process-document/
Ja osobiście wolę używać starego dobrego ES6, niż tych nowszych elementów języka, które są w fazie eksperymentalnej jeszcze.
@LukeJL
Odpowiem w poscie bo komentarze niewygodne dla kodu.
Z drugiej strony definicje dekoratora dotyczą zwykle klas, co niekoniecznie się będzie tłumaczyć 1:1 do programowania funkcyjnego.
W FP wzorzec dekoratora pojawia się tak samo, choć nie jest to jakiś specjalny koncept jak w OOP (dla którego warto by był tworzyć osobny syntax) - ot po prostu konkretny sposób składania funkcji. Założenia są dokładnie te same - stworzyć nowy byt rozszerzający funkcjonalność, implementujący ten sam interfejs (w przypadku funkcji typ funkcji jest "interfejsem"), tak by opakowaną funkcję / klasę / metodę można było użyć w miejscu nieopakowanej funkcji / klasy / metody bez zmian w kodzie.
Na przykładzie loggera:
a) osobny dekorator zwracjaacy funkcję o tym samym typie co funkcja pierwotna:
// original:
// type F = (number) => number
const square = a => a ** 2
const logger = fn => input => {
console.log(input)
const output = fn(input)
console.log(output)
return output;
}
// decorated:
// type F' = (number) => number
const squareWithLogging = logger(square)
square(7)
squareWithLogging(7)
a) dekorator za pomocą kompozycji (także ten sam typ dekorowanej funkcji co funkcji wynikowej):
// type F = (number) => number
const square = a => a ** 2
const log = a => {
console.log(a)
return a
}
// type F' = (number) => number
const squareWithLogging = a => log(square(log(a)))
square(7)
squareWithLogging(7)
Udekorowanej funkcji możesz teraz użyć wszędzie, gdzie była używana funkcja nieudekorowana:
const arr = [1, 2, 3]
const resultA = arr
.filter(x => x % 2 !== 0)
.map(square)
.reduce((acc, x) => acc + x)
const resultB = arr
.filter(x => x % 2 !== 0)
.map(squareWithLogging)
.reduce((acc, x) => acc + x)
console.log({
resultA,
resultB
})
Twój przykład nie spełnia wymagań (niezgodne typy):
// original:
// type F = (Props) => Component
const Hello = ({ name }) => (
<p>Hello {name}</p>
)
const useMe = Component => () => <Component name="Maciek" />
// pseudo decorated:
// type F' = (void) => Component
const DecoratedHello = useMe(Hello) // oops, not the same type anymore
class App extends Component {
render() {
return (
<div className="App">
<Hello name="Maciek" />
<DecoratedHello name="John"/> {/* <--- props lost in limbo ;) */}
</div>
);
}
}