Created
May 14, 2020 02:06
-
-
Save danielrob/777821c429503f9cbd02e0a940065c1c to your computer and use it in GitHub Desktop.
Redux Input
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { toPath } from "lodash"; | |
import { is, path, assocPath, always } from "ramda"; | |
import React, { useContext } from "react"; | |
import { useDispatch, useSelector } from "react-redux"; | |
import { Context, ReduxInputContext } from "./ReduxInputContext"; | |
/** | |
* ReduxInput connects any standard input component to the redux store where a | |
* "standard input component" is any component accepting e.g. value and onChange props. | |
* | |
* @param {function} Component - the component to connect to the store. | |
* @param {function} selector - selects state containing the input value to be acted on from the redux store. | |
* @param {function} action - the action to dispatch whenever the underlying onChange is fired. | |
* @param {string|array} actOn - sub-path of the selected state to read/write the input value to. | |
* @param {function} parse - a transformator to transform raw onChange value to store value. | |
* @param {function} format - a transformator to transform store value to raw input value. | |
* @param {object} props - props to be explicitly passed to the underlying Component | |
*/ | |
const ReduxInput = ({ | |
Component, | |
selector, | |
action, | |
actOn, | |
parse, | |
format, | |
props, | |
...rest | |
}) => { | |
const dispatch = useDispatch(); | |
const { cSelector, cAction } = useContext(Context) || {}; | |
const state = useSelector(selector || cSelector || fallbackSelector); | |
const value = actOn ? path(toPath(actOn), state) : state; | |
const formattedValue = is(Function, format) ? format(value) : value; | |
const callback = (onChangeValue) => { | |
const eventValue = onChangeValue?.target?.value; | |
const nextValue = eventValue === undefined ? onChangeValue : eventValue; | |
const parsedValue = is(Function, parse) ? parse(nextValue) : nextValue; | |
const finalPayload = actOn | |
? assocPath(toPath(actOn), parsedValue, state) | |
: parsedValue; | |
if (is(Function, action || cAction)) { | |
dispatch((action || cAction)(finalPayload)); | |
} | |
}; | |
return ( | |
<Component | |
value={formattedValue} | |
onChange={callback} | |
{...props} | |
{...rest} | |
/> | |
); | |
}; | |
const fallbackSelector = always({}); | |
export { ReduxInputContext, ReduxInput }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
const Context = React.createContext(); | |
const ReduxInputContext = ({ | |
selector, | |
action, | |
children, | |
Component = React.Fragment, | |
...props | |
}) => ( | |
<Component {...props}> | |
<Context.Provider value={{ cSelector: selector, cAction: action }}> | |
{children} | |
</Context.Provider> | |
</Component> | |
); | |
export { ReduxInputContext, Context }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment