From dedf8025a547d698d9f2e62f0897493d61ffadd5 Mon Sep 17 00:00:00 2001 From: Noah Loomans Date: Tue, 26 Jun 2018 22:25:55 +0200 Subject: Use mapStateToProps for router simplification --- src/client/react/components/container/Menu.js | 47 ++++++++++++---------- src/client/react/components/container/Results.js | 30 +++++++------- .../react/components/container/RoomFinder.js | 40 +++++++++--------- src/client/react/components/container/Search.js | 14 +++---- .../react/components/container/WeekSelector.js | 29 +++++++------ src/client/react/components/page/User.js | 16 ++++++-- src/client/react/lib/url.js | 22 +++++----- 7 files changed, 107 insertions(+), 91 deletions(-) diff --git a/src/client/react/components/container/Menu.js b/src/client/react/components/container/Menu.js index 474444d..85fa785 100644 --- a/src/client/react/components/container/Menu.js +++ b/src/client/react/components/container/Menu.js @@ -26,38 +26,32 @@ import { Button, ButtonIcon } from 'rmwc/Button'; import { SimpleMenu, MenuItem } from 'rmwc/Menu'; import { Icon } from 'rmwc/Icon'; import users from '../../users'; -import { setUser, userFromMatch } from '../../lib/url'; +import { makeSetUser, userFromMatch } from '../../lib/url'; import './Menu.scss'; class Menu extends React.Component { static propTypes = { - // redux - dispatch: PropTypes.func.isRequired, + setUser: PropTypes.func.isRequired, + user: PropTypes.string, + showRoomFinder: PropTypes.func.isRequired, + } - // react-router - match: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, - history: PropTypes.object.isRequired, + static defaultProps = { + user: null, } onItemSelected(index) { switch (index) { case 'room_finder': { - const { - match, - location, - history, - dispatch, - } = this.props; - const user = userFromMatch(match); + const { setUser, user, showRoomFinder } = this.props; if (user == null || users.byId[user].type !== 'r') { // We are not currently viewing a room, correct the situation. - setUser(users.allRoomIds[0], location, history); + setUser(users.allRoomIds[0]); } - dispatch({ type: 'ROOM_FINDER/SHOW' }); + showRoomFinder(); break; } default: @@ -73,7 +67,7 @@ class Menu extends React.Component { -)} + )} onSelected={(event) => { // Send the `data-type` of the selected this.onItemSelected(event.detail.item.dataset.type); @@ -81,20 +75,20 @@ class Menu extends React.Component { > -Voeg label toe + Voeg label toe -Maak favoriet + Maak favoriet
-Lokaal zoeken + Lokaal zoeken -Oud rooster gebruiken + Oud rooster gebruiken
@@ -102,4 +96,13 @@ Oud rooster gebruiken } } -export default withRouter(connect()(Menu)); +const mapStateToProps = (state, { match, location, history }) => ({ + user: userFromMatch(match), + setUser: makeSetUser(location, history), +}); + +const mapDispatchToProps = dispatch => ({ + showRoomFinder: () => dispatch({ type: 'ROOM_FINDER/SHOW' }), +}); + +export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Menu)); diff --git a/src/client/react/components/container/Results.js b/src/client/react/components/container/Results.js index 314bbca..c52e43e 100644 --- a/src/client/react/components/container/Results.js +++ b/src/client/react/components/container/Results.js @@ -25,7 +25,7 @@ import { connect } from 'react-redux'; import { withRouter } from 'react-router-dom'; import users from '../../users'; -import { setUser, userFromMatch } from '../../lib/url'; +import { makeSetUser, userFromMatch } from '../../lib/url'; import Result from '../presentational/Result'; import './Results.scss'; @@ -37,9 +37,8 @@ class Results extends React.Component { selectedResult: PropTypes.string, // react-router - match: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, - history: PropTypes.object.isRequired, + user: PropTypes.string, + setUser: PropTypes.func.isRequired, // redux dispatch: PropTypes.func.isRequired, @@ -47,6 +46,7 @@ class Results extends React.Component { static defaultProps = { selectedResult: null, + user: null, }; render() { @@ -54,12 +54,10 @@ class Results extends React.Component { searchText, results, selectedResult, - match, - location, - history, + user, + setUser, dispatch, } = this.props; - const user = userFromMatch(match); const isExactMatch = ( user != null && searchText === users.byId[user].value @@ -74,19 +72,19 @@ class Results extends React.Component { minHeight: isExactMatch ? 0 : results.length * 54, }} > - {!isExactMatch && results.map(userId => ( + {!isExactMatch && results.map(resultUser => ( { - if (userId === user) { + if (resultUser === user) { // EDGE CASE: The user is set if the user changes, but it doesn't // change if the result is already the one we are viewing. // Therefor, we need to dispatch the SET_USER command manually. dispatch({ type: 'SEARCH/SET_USER', user }); } else { - setUser(userId, location, history); + setUser(resultUser); } }} /> @@ -96,7 +94,9 @@ class Results extends React.Component { } } -const mapStateToProps = state => ({ +const mapStateToProps = (state, { match, location, history }) => ({ + user: userFromMatch(match), + setUser: makeSetUser(location, history), results: state.search.results, searchText: state.search.text, selectedResult: state.search.result, diff --git a/src/client/react/components/container/RoomFinder.js b/src/client/react/components/container/RoomFinder.js index 0d296a2..f6e7ac6 100644 --- a/src/client/react/components/container/RoomFinder.js +++ b/src/client/react/components/container/RoomFinder.js @@ -24,7 +24,7 @@ import { connect } from 'react-redux'; import { withRouter } from 'react-router-dom'; import { Button, ButtonIcon } from 'rmwc/Button'; import users from '../../users'; -import { setUser, userFromMatch } from '../../lib/url'; +import { makeSetUser, userFromMatch } from '../../lib/url'; import './RoomFinder.scss'; @@ -32,38 +32,36 @@ class RoomFinder extends React.Component { static propTypes = { // redux isVisible: PropTypes.bool.isRequired, - dispatch: PropTypes.func.isRequired, + onHide: PropTypes.func.isRequired, // react-router - match: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, - history: PropTypes.object.isRequired, + user: PropTypes.string.isRequired, + setUser: PropTypes.func.isRequired, } componentWillMount() { - const { isVisible, match, dispatch } = this.props; - const user = userFromMatch(match); + const { isVisible, user, onHide } = this.props; if (isVisible && users.byId[user].type !== 'r') { // We are not currently viewing a room, so just hide. - dispatch({ type: 'ROOM_FINDER/HIDE' }); + onHide(); } } componentWillReceiveProps(nextProps) { - const { isVisible, match, dispatch } = nextProps; + const { isVisible, user, onHide } = nextProps; - const user = userFromMatch(match); if (isVisible && users.byId[user].type !== 'r') { // We are not currently viewing a room, so just hide. - dispatch({ type: 'ROOM_FINDER/HIDE' }); + onHide(); } } changeRoom(change) { - const { match, location, history } = this.props; + const { user, setUser } = this.props; const { allRoomIds } = users; - const currentRoom = userFromMatch(match); + + const currentRoom = user; const currentRoomIndex = allRoomIds.indexOf(currentRoom); let nextRoomIndex = currentRoomIndex + change; if (nextRoomIndex < 0) { @@ -73,11 +71,11 @@ class RoomFinder extends React.Component { } const nextRoom = allRoomIds[nextRoomIndex]; - setUser(nextRoom, location, history); + setUser(nextRoom); } render() { - const { isVisible, dispatch } = this.props; + const { isVisible, onHide } = this.props; if (!isVisible) { return
; } @@ -93,7 +91,7 @@ class RoomFinder extends React.Component {
@@ -102,8 +100,14 @@ class RoomFinder extends React.Component { } } -const mapStateToProps = state => ({ +const mapStateToProps = (state, { match, location, history }) => ({ + user: userFromMatch(match), + setUser: makeSetUser(location, history), isVisible: state.isRoomFinderVisible, }); -export default withRouter(connect(mapStateToProps)(RoomFinder)); +const mapDispatchToProps = dispatch => ({ + onHide: () => dispatch({ type: 'ROOM_FINDER/HIDE' }), +}); + +export default withRouter(connect(mapStateToProps, mapDispatchToProps)(RoomFinder)); diff --git a/src/client/react/components/container/Search.js b/src/client/react/components/container/Search.js index 5f00384..65b2933 100644 --- a/src/client/react/components/container/Search.js +++ b/src/client/react/components/container/Search.js @@ -26,7 +26,7 @@ import { withRouter } from 'react-router-dom'; import SearchIcon from 'react-icons/lib/md/search'; -import { setUser, userFromMatch } from '../../lib/url'; +import { makeSetUser, userFromMatch } from '../../lib/url'; import users from '../../users'; import Menu from './Menu'; @@ -43,9 +43,7 @@ class Search extends React.Component { // react-router match: PropTypes.object.isRequired, - location: PropTypes.object.isRequired, - history: PropTypes.object.isRequired, - + setUser: PropTypes.func.isRequired, // redux dispatch: PropTypes.func.isRequired, }; @@ -99,8 +97,7 @@ class Search extends React.Component { selectedResult, results, match, - location, - history, + setUser, dispatch, } = this.props; @@ -131,7 +128,7 @@ class Search extends React.Component { // Therefor, we need to dispatch the SET_USER command manually. dispatch({ type: 'SEARCH/SET_USER', user: urlUser }); } else if (result) { - setUser(result, location, history); + setUser(result); } break; @@ -186,7 +183,8 @@ class Search extends React.Component { } } -const mapStateToProps = state => ({ +const mapStateToProps = (state, { location, history }) => ({ + setUser: makeSetUser(location, history), results: state.search.results, searchText: state.search.text, selectedResult: state.search.selected, diff --git a/src/client/react/components/container/WeekSelector.js b/src/client/react/components/container/WeekSelector.js index 80ad754..19a3947 100644 --- a/src/client/react/components/container/WeekSelector.js +++ b/src/client/react/components/container/WeekSelector.js @@ -21,27 +21,27 @@ import React from 'react'; import PropTypes from 'prop-types'; import moment from 'moment'; +import { connect } from 'react-redux'; import { withRouter } from 'react-router-dom'; import ArrowBackIcon from 'react-icons/lib/md/arrow-back'; import ArrowForwardIcon from 'react-icons/lib/md/arrow-forward'; import purifyWeek from '../../lib/purifyWeek'; -import { setWeek, weekFromLocation } from '../../lib/url'; +import { makeSetWeek, weekFromLocation } from '../../lib/url'; import './WeekSelector.scss'; class WeekSelector extends React.Component { static propTypes = { // react-router - location: PropTypes.object.isRequired, - history: PropTypes.object.isRequired, + week: PropTypes.number.isRequired, + setWeek: PropTypes.func.isRequired, }; getWeekText() { - const { location } = this.props; + const { week } = this.props; - const week = weekFromLocation(location); const currentWeek = moment().week(); switch (week) { @@ -57,17 +57,11 @@ class WeekSelector extends React.Component { } updateWeek(change) { - const { location, history } = this.props; - const week = weekFromLocation(location); - + const { week, setWeek } = this.props; const newWeek = purifyWeek(week + change); - const isCurrentWeek = moment().week() === newWeek; - setWeek( - isCurrentWeek ? undefined : newWeek, - location, - history, - ); + const isCurrentWeek = moment().week() === newWeek; + setWeek(isCurrentWeek ? undefined : newWeek); } render() { @@ -87,4 +81,9 @@ class WeekSelector extends React.Component { } } -export default withRouter(WeekSelector); +const mapStateToProps = (state, { location, history }) => ({ + week: weekFromLocation(location), + setWeek: makeSetWeek(location, history), +}); + +export default withRouter(connect(mapStateToProps)(WeekSelector)); diff --git a/src/client/react/components/page/User.js b/src/client/react/components/page/User.js index 4b9af64..af14188 100644 --- a/src/client/react/components/page/User.js +++ b/src/client/react/components/page/User.js @@ -20,6 +20,7 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; import { Redirect } from 'react-router-dom'; import { Elevation } from 'rmwc/Elevation'; import Search from '../container/Search'; @@ -33,12 +34,15 @@ import './User.scss'; class UserPage extends React.Component { static propTypes = { // react-router - match: PropTypes.object.isRequired, + user: PropTypes.string, }; + static defaultProps = { + user: null, + } + render() { - const { match } = this.props; - const user = userFromMatch(match); + const { user } = this.props; if (!user) { // Invalid user, redirect to index. @@ -66,4 +70,8 @@ class UserPage extends React.Component { } } -export default UserPage; +const mapStateToProps = (state, { match }) => ({ + user: userFromMatch(match), +}); + +export default connect(mapStateToProps)(UserPage); diff --git a/src/client/react/lib/url.js b/src/client/react/lib/url.js index be09acf..c94383c 100644 --- a/src/client/react/lib/url.js +++ b/src/client/react/lib/url.js @@ -43,16 +43,20 @@ export function weekFromLocation(location) { return purifyWeek(parseInt(weekStr, 10)); } -export function setUser(userId, location, history) { - const query = location.search; - history.push(`/${userId}${query}`); +export function makeSetUser(location, history) { + return (userId) => { + const query = location.search; + history.push(`/${userId}${query}`); + }; } -export function setWeek(week, location, history) { - const query = queryString.stringify({ - ...queryString.parse(location.search), - week, - }); +export function makeSetWeek(location, history) { + return (week) => { + const query = queryString.stringify({ + ...queryString.parse(location.search), + week, + }); - history.push(`${location.pathname}?${query}`); + history.push(`${location.pathname}?${query}`); + }; } -- cgit v1.1