Sebastian Herrmann
A software-developing peep.
Software Developer at
@HerrHerrmann
import * as _ from 'lodash';
const activeUsernames = _(users)
.filter({ isActive: true })
.map('username')
.sort()
.value();
const isMature = age => age > 17;
const getAge = user => user.profile.age;
import { map } from 'lodash/fp';
const getName = user => user.name;
const getNames = map(getName);
partial application
const userNames = getNames(users);
// ❌ mutability
const user = { name: 'Sarah' };
user.name = 'Buffy';
users.push(user);
// ✅ immutability
const user = { name: 'Sarah' };
const changedUser = { ...user, name: 'Buffy' };
const usersWithSarah = [ ...users, changedUser ];
// ❌ impure function
const getStateImpure = () => window.appState.name;
// ✅ pure function
const getState = currentWin => currentWin.appState.name;
// ✅ via lodash/fp
const getState = get('appState.name');
import * as _ from 'lodash';
const devNames = _(users)
.filter(isDeveloper)
.map(getName)
.value();
import { compose, filter, map, toUpper } from 'lodash/fp';
const getDevNames = compose(
map(getName),
filter(isDeveloper),
);
const devNames = getDevNames(users);
const getDevNamesUpper = compose(
toUpper,
getDevNames,
);
const multiplyByTwo = multiply(2);
map(multiplyByTwo, [1, 2, 3, 4]);
// => [2, 4, 6, 8]
const UserListPageWithData = withData(
{
users: api.loadUsers
},
UserListPage
);
// => UserListPage called with prop "users"
const getManagers =
users => users.filter(user => user.isManager);
const getNamesOfManagers =
users => getManagers(users).map(user => user.name);
// VS
const getManagers = filter(get('isManager'));
const getNamesOfManagers = compose(map(get('name')), getManagers);
// ^ pointfree functions!
import { compose } from 'lodash/fp';
import { mapProps, withState } from 'recompose';
import { withAppContext } from '../../hoc/withAppContext';
// "Plain" stateless component
const ReadMoreText = (/*...*/) => {/*...*/};
// Component with state and context
export default compose(
withAppContext,
withState('expanded', 'setExpanded', false),
mapProps(sanitizeText),
)(ReadMoreText);
export default compose(
withAppContext,
withData({
resolve: {
summaries: api.meetingSummaries.fetchSummaries,
},
}),
Component => props => (
<Component {...props}
summaries={map(createSummaryFromDto, props.summaries)}
/>
),
withLocalStorage('meetings-overview-page-view'),
withStore(undefined, mapDispatchToProps)
)(MeetingOverviewPage);
const CommentCountWithLoader = withData({
resolve: {
commentCountResponse:
({ objective }) => batchRequest(/* ... */)
},
pendingComponent: PendingCommentCount,
errorComponent: CommentCountError
})(CommentCount);
export default ifVisible({
pendingComponent: InvisibleCommentCount
})(CommentCountWithLoader);
Use FP as much as you like!
(But don't throw consistency overboard.)
Questions? Comments? Opinions?
Slides: bit.ly/fp-react
Costume by SHOXXX (www.shoxxxboxxx.com)
By Sebastian Herrmann
I'll highlight how we're using FP in the frontend in combination with JavaScript and React to build readable and reusable functions and components. (Presented at BerlinJS in October 2018.)