Gathering detailed insights and metrics for react-parm
Gathering detailed insights and metrics for react-parm
Gathering detailed insights and metrics for react-parm
Gathering detailed insights and metrics for react-parm
npm install react-parm
70.8
Supply Chain
95.2
Quality
75.4
Maintenance
100
Vulnerability
100
License
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
18 Stars
117 Commits
1 Forks
3 Watching
5 Branches
1 Contributors
Updated on 13 Jan 2022
JavaScript (100%)
Cumulative downloads
Total Downloads
Last day
-34.2%
613
Compared to previous day
Last week
-5.8%
4,062
Compared to previous week
Last month
-16.9%
17,278
Compared to previous month
Last year
11.6%
184,853
Compared to previous year
3
33
Handle react classes with more functional purity
react-parm
is a thin abstraction providing partial-application methods that allow you to handle react
classes with much more functional purity. This allows for better encapsulation, greater separation of concerns, and simplified testing. When combined with destructuring, it also improves readability and comprehension.
1import React from "react"; 2import { createElementRef, createMethod } from "react-parm"; 3 4export const componentDidMount = ({ getFoo, props }) => 5 props.shouldGetFoo && getFoo(); 6 7export const onClickGetBar = ({ getBar }, [event]) => 8 getBar(event.currentTarget.dataset.baz); 9 10export default class App extends React.Component { 11 // lifecycle methods 12 componentDidMount = createMethod(this, componentDidMount); 13 14 // refs 15 element = null; 16 17 // instance methods 18 onClickGetBar = createMethod(this, onClickGetBar); 19 20 render() { 21 return ( 22 <button 23 data-baz="quz" 24 onClick={this.onClickGetBar} 25 ref={createElementRef(this, "element")} 26 > 27 Go get bar! 28 </button> 29 ); 30 } 31}
Create a functional instance or lifecycle method, which will receive the full instance as the first parameter.
createMethod(instance: ReactComponent, method: function, ...extraArgs: Array
1import React from "react"; 2import { createMethod } from "react-parm"; 3 4export const componentDidMount = ({ setState }) => 5 setState(() => ({ isMounted: true })); 6 7export const onClickDoThing = ({ props }, [event], [withStuff]) => 8 props.doThing(event.currentTarget, withStuff); 9 10export default class App extends Component { 11 state = { 12 isMounted: false 13 }; 14 15 componentDidMount = createMethod(this, componentDidMount); 16 onClickDoThing = createMethod(this, onClickDoThing, true); 17 18 render() { 19 return ( 20 <div> 21 <h3>Welcome to doing the thing</h3> 22 23 <button onClick={this.onClickDoThing}>Do the thing</button> 24 </div> 25 ); 26 } 27}
If you want this method to be memoized in an instance-specific way, you can assign the function that will memoize the method to the memoizer
property on the function you create the method from.
1import memoize from "micro-memoize"; 2 3const setCount = ({ setState }, [count]) => setState({ count }); 4 5setCount.memoizer = memoize;
This will automatically wrap the method you pass to createMethod
in the memoizer
.
Create a value to assign to the instance based on a functional method which will receive the full instance as the first parameter.
createValue(instance: ReactComponent, method: function, ...extraArgs: Array
1import React from "react"; 2import { createValue } from "react-parm"; 3 4export const getLength = ({ props }) => { 5 return props.foo.length; 6}; 7 8export default class App extends Component { 9 length = createValue(this, getLength); 10 11 render() { 12 return <div>The length of the foo parameter is {this.length}</div>; 13 } 14}
Create a functional render method, which will receive the props
as the first parameter, the full instance as the second parameter, and any arguments passed to it as the third parameter.
createRender(instance: ReactComponent, render: function): (props: Object, instance: ReactComponent, args: Array
1import React from "react"; 2import { createMethod, createRender } from "react-parm"; 3 4export const componentDidMount = ({ setState }) => 5 setState(() => ({ isMounted: true })); 6 7export const DoTheThing = ({ doThing }, { state: { isMounted } }) => { 8 return ( 9 <div> 10 <h3>Welcome to doing the mounted thing</h3> 11 12 <span>Am I mounted? {isMounted ? "YES!" : "No :("}</span> 13 14 <button onClick={doThing}>Do the thing</button> 15 </div> 16 ); 17}; 18 19export default class App extends Component { 20 state = { 21 isMounted: false 22 }; 23 24 componentDidMount = createMethod(this, componentDidMount); 25 26 render = createRender(this, DoTheThing); 27}
NOTE: The difference in signature from createMethod
is both for common-use purposes, but also because it allows linting tools to appropriately lint for PropTypes
.
Create a functional render props method, which will receive the props
passed to it as the first parameter, the full instance as the second parameter, and any additional arguments passed to it as the third parameter.
createRenderProps(instance: ReactComponent, render: function): (props: Object, instance: ReactComponent, remainingArgs: Array
1import React from "react"; 2import { createMethod, createRenderProps } from "react-parm"; 3 4const RenderPropComponent = ({ children }) => ( 5 <div>{children({ stuff: "passed" })}</div> 6); 7 8const renderProps = (props, instance) => ( 9 <div> 10 {props.stuff} 11 12 <button onClick={instance.props.doThing}>Do the thing</button> 13 </div> 14); 15 16export const DoTheThing = ({ doThing }) => ( 17 <RenderPropComponent>{renderProps}</RenderPropComponent> 18); 19 20export default class App extends Component { 21 state = { 22 isMounted: false 23 }; 24 25 renderProps = createRenderProps(this, renderProps); 26 27 render = createRender(this, DoTheThing); 28}
NOTE: The main difference between createRender
and createRenderProps
is the first props
argument. In the case of createRender
, it is the props
of the instance
the method is bound to, whereas in the case of createRenderProps
it is the props
argument passed to it directly.
Create a functional component with all available instance-based methods, values, and refs a Component
class has.
createComponent(render: function, options: Object): ReactComponent
1import React from "react"; 2import { createComponent } from "react-parm"; 3 4export const state = { 5 isMounted: false 6}; 7 8export const componentDidMount = ({ setState }) => 9 setState(() => ({ isMounted: true })); 10 11export const onClickDoThing = ({ props }, [event]) => 12 props.doThing(event.currentTarget); 13 14export const DoTheThing = ({ doThing }, { onClickDoThing }) => ( 15 <div> 16 <h3>Welcome to doing the thing</h3> 17 18 <button onClick={doThing && onClickDoThing}>Do the thing</button> 19 </div> 20); 21 22DoTheThing.displayName = "DoTheThing"; 23 24DoTheThing.propTypes = { 25 doThing: PropTypes.func.isRequired 26}; 27 28export default createComponent(DoTheThing, { 29 componentDidMount, 30 onClickDoThing, 31 state 32});
NOTE: Starting in version 2.6.0
, the options
can be applied via currying:
1export default createComponent({ componentDidMount, onClickDoThing, state })( 2 DoTheThing 3);
The component will be parmed with createRender
, and the properties passed in options
will be handled as follows:
Lifecycle methods will be parmed with createMethod
Instance methods will be parmed with createMethod
, unless:
It has a static property of isRender
set to true
, in which case it will be parmed with createRender
. Example:
1const renderer = ({ foo }) => <div>{foo}</div>; 2 3renderer.isRender = true;
It has a static property of isRenderProps
set to true
, in which case it will be parmed with createRenderProps
. Example:
1const renderProps = ({ children }) => <div>{children({child: 'props')}</div>; 2 3renderProps.isRenderProps = true;
Instance values will be assigned to the instance
There are also some additional properties that are treated outside the context of assignment to the instance:
getInitialState
=> if a method is passed, then it is parmed and used to derive the initial state instead of the static state
propertygetInitialValues
=> If a method is passed, then it is parmed and used to derive initial instance values
{foo: 'bar'}
will result in instance.foo
being "bar"
isPure
=> should PureComponent
be used to construct the underlying component class instead of Component
(defaults to false
)onConstruct
=> If a method is passed, then it is called with the instance as parameter at the end of constructionNOTE: Any additional static values / methods you apply to the render component will be re-assigned to the parmed component.
Create a method that will assign the Component requested to an instance value using a ref callback.
createComponentRef(instance: ReactComponent, ref: string): (component: HTMLElement | ReactComponent) => void
1import React from "react"; 2import { createElementRef } from "react-parm"; 3 4export default class App extends Component { 5 component = null; 6 7 render() { 8 return ( 9 <SomeOtherComponent ref={createComponentRef(this, "component")}> 10 We captured the component instance! 11 </SomeOtherComponent> 12 ); 13 } 14}
The ref
string value passed will be the key that will be used in the assignment to the instance
.
Create a method that will assign the DOM node of the component requested to an instance value using a ref callback.
createElementRef(instance: ReactComponent, ref: string): (component: HTMLElement | ReactComponent) => void
1import React from "react"; 2import { createElementRef } from "react-parm"; 3 4export default class App extends Component { 5 element = null; 6 7 render() { 8 return ( 9 <SomeOtherComponent ref={createElementRef(this, "element")}> 10 We found the DOM node! 11 </SomeOtherComponent> 12 ); 13 } 14}
The ref
string value passed will be the key that will be used in the assignment to the instance
.
Create a method that will assign both the DOM node of the component requested and the component itself to a namespaced instance value using a ref callback.
createCombinedRef(instance: ReactComponent, ref: string): (component: HTMLElement | ReactComponent) => void
1import React from "react"; 2import { createCombinedRef } from "react-parm"; 3 4export default class App extends Component { 5 someOtherComponent = null; 6 7 render() { 8 return ( 9 <SomeOtherComponent ref={createCombinedRef(this, "someOtherComponent")}> 10 I have the best of both worlds! this.someOtherComponent will look like "{component: SomeOtherComponent, element: div}". 11 </SomeOtherComponent> 12 ); 13 } 14}
The value assigned will be an object with component
and element
properties, which reflect the component and the DOM node for that component respectively. The ref
string value passed will be the key that will be used in the assignment to the instance
.
Create a custom PropTypes validation method.
createPropType(validator: function): (metadata: Object) => (Error|null)
1import { createPropType } from "react-parm"; 2 3export const isFoo = createPropType(({ component, name, value }) => 4 value === "foo" 5 ? null 6 : new Error( 7 `The prop "${name}" is "${value}" in ${component}, when it should be "foo"!` 8 ); 9);
The full shape of the metadata
object passed to createPropType
:
1{ 2 component: string, // the name of the component 3 key: string, // the key that is being validated 4 name: string, // the name of the prop being validated 5 path: string, // the full path (if nested) of the key being validated 6 props: any, // the props object 7 value: any // the value of the prop passed 8}
Please note that usage may result in different values for these keys, based on whether the custom prop type is used in arrayOf
/ objectOf
or not.
When used in arrayOf
or objectOf
:
key
represents the nested key being validatedname
represents the name of the prop that was passedpath
represents the full path being validatedExample:
1const isArrayOfFoo = createPropType( 2 ({ component, key, name, path, value }) => { 3 value === "foo" 4 ? null 5 : new Error( 6 `The key "${key}" for prop "${name}" at path ${path} is "${value}" in ${component}, when it should be "foo"!` 7 ); 8 } 9); 10... 11<SomeComponent bar={['baz']}> 12// The key "0" for prop "bar" at path "bar[0]" is "baz" in "SomeComponent", when it should be "foo"!
When the prop type is used in any context other than arrayOf
/ objectOf
, then key
, name
, and path
will all be the same value.
PARM is an acronym, standing for Partial-Application React Method. Also, why not parm? It's delicious.
Standard stuff, clone the repo and npm install
dependencies. The npm scripts available:
build
=> run rollup to build development and production dist
filesdev
=> run webpack dev server to run example app / playgroundlint
=> run ESLint against all files in the src
folderlint: fix
=> runs lint
with --fix
prepublish
=> runs prepublish:compile
when publishingprepublish:compile
=> run lint
, test:coverage
, transpile:lib
, transpile:es
, and build
test
=> run AVA test functions with NODE_ENV=test
test:coverage
=> run test
but with nyc
for coverage checkertest:watch
=> run test
, but with persistent watchertranspile:lib
=> run babel against all files in src
to create files in lib
transpile:es
=> run babel against all files in src
to create files in es
, preserving ES2015 modules (for
pkg.module
)No vulnerabilities found.
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Reason
53 existing vulnerabilities detected
Details
Score
Last Scanned on 2024-11-18
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More