Miลosz Piechocki
const mountains = [
'Mount Everest',
'Mont Blanc',
'Kazbek',
];
mountains.map(mountain => toLower(mountain));
mountains.map(toLower);
Never mention the data!
mountains.map(mountain => toLower(mountain));
const numbers = [ 1, 2, 3, 4, 5];
function multiply(a, b) { return a * b; }
numbers.map(x => multiply(2, x));
numbers.map(multiply(2));
const multiply = (a) => {
return (b) => {
return a * b;
}
};
const multiply = a => b => a * b;
numbers.map(multiply(2));
import {curry} from 'ramda';
const multiply = curry((a, b) => a * b);
numbers.map(multiply(2));
const postIds = [ 1, 2, 3, 4, 5 ];
function fetchPost(postId, secret) {
return fetch(`https://website.com/posts/${postId}`, {
headers: {
'secret-key': secret
}
});
}
const fetchPostCurried = curry(fetchPost);
postIds.map(fetchPostCurried(user.secretKey));
function fetchPost(postId, secret) {
// ...
}
function fetchPost(secret, postId) {
// ...
}
react-redux
const FilterLink = connect(
mapStateToProps,
mapDispatchToProps
)(Link);
https://redux.js.org/api/compose
const getIntValue = pipe(getValue, parseInt);
<div id="app">
<input class="post-id" />
<input class="post-id" />
<input class="post-id" />
</div>
function limit(x) {
return Math.max(Math.min(x, 100), 0);
}
function fetchPost(id) { /* ... */ }
const inputs = Array.from(
document.getElementsByClassName('post-id'));
inputs.map(input => fetchPost(limit(parseInt(input.value))));
inputs.map(input => fetchPost(limit(parseInt(input.value))));
vs
inputs.map(pipe(
prop('value'),
parseInt,
clamp(0, 100),
fetchPost,
));
inputs.map(
prop('value')
|> parseInt
|> limit
|> fetchPost
)
const image$ = nameInput$.pipe(
map(() => nameInputEl.value),
filter(name => name.length >= 3),
debounceTime(500),
mergeMap(name =>
fetch(`https://dog.ceo/api/breed/${name}/images/random`)),
mergeMap(response => response.json()),
map(result => result.message)
);
import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import DevTools from './containers/DevTools'
import reducer from '../reducers'
โ
const store = createStore(
reducer,
compose(
applyMiddleware(thunk),
DevTools.instrument()
)
);
https://redux.js.org/api/compose
Donโt confuse simplicity with familiarity
Old Chineese proverb
const state = {
posts: [
{ title: 'A', content: '' },
{ title: 'B', content: '' },
{ title: 'C', content: '' }
],
isLoading: false,
paging: {
pageNumber: 5
}
};
const postsRequestFinished = (state, payload) => {
return {
...state,
posts: state.posts.concat(payload.posts),
isLoading: false,
paging: {
...state.paging,
pageNumber: state.paging.pageNumber + 1
}
}
};
const postsRequestFinished = (state, { posts }) =>
evolve(
{
posts: concat(posts),
isLoading: always(false),
paging: evolve({ pageNumber: inc })
},
state
);
const image$ = nameInput$.pipe(
map(() => nameInputEl.value),
filter(name => name.length >= 3),
debounceTime(500),
mergeMap(name =>
getJSON(`https://dog.ceo/api/breed/${name}/images/random`)),
map(result => result.message)
);
const nameInputElValue = () => nameInputEl.value;
const dogImageUrl = name =>
`https://dog.ceo/api/breed/${name}/images/random`;
const image$ = nameInput$.pipe(
map(nameInputElValue),
filter(pipe(length, gt(__, 3))),
debounceTime(500),
mergeMap(pipe(dogImageUrl, getJSON)),
map(prop('message'))
);
const state = {
shop: {
items: [
{ name: 'A', value: 100 },
{ name: 'B', value: 200 },
],
taxPercent: 10,
}
};
const shopItemsSelector = state => state.shop.items;
const taxPercentSelector = state => state.shop.taxPercent;
const subtotalSelector = createSelector(
shopItemsSelector,
items => items.reduce((acc, item) => acc + item.value, 0)
);
const taxSelector = createSelector(
subtotalSelector,
taxPercentSelector,
(subtotal, taxPercent) => subtotal * (taxPercent / 100)
);
Based on code from: https://github.com/reduxjs/reselect
const shopItemsSelector = path(['shop', 'items']);
const taxPercentSelector = path(['shop', 'taxPercent']);
const subtotalSelector = createSelector(
shopItemsSelector,
reduce(useWith(add, [identity, prop('value')]), 0),
);
const taxSelector = createSelector(
subtotalSelector,
taxPercentSelector,
useWith(multiply, [identity, divide(__, 100)]),
);
const format = (actual, expected) => {
const variants = expected.join(โ, โ);
return `Value ${actual} is not expected here.
Possible variants are: ${variants}`;
}
const format = converge(
unapply(join(' ')),
[
always('Value'),
nthArg(0),
always('is not expected here. Possible variants are:'),
compose(join(', '), nthArg(1))
]
);
Example from: Two Years of Functional Programming in JavaScript: Lessons Learned
ramdalodash - curry, partiallodash/fplodash vs lodash/fplodash
map(mountains, toLower);
lodash/fp
fp.map(toLower)(mountains);
https://github.com/lodash/lodash/wiki/FP-Guide