Gathering detailed insights and metrics for @cleanweb/react
Gathering detailed insights and metrics for @cleanweb/react
Gathering detailed insights and metrics for @cleanweb/react
Gathering detailed insights and metrics for @cleanweb/react
npm install @cleanweb/react
Typescript
Module System
Min. Node Version
Node Version
NPM Version
69.2
Supply Chain
98.4
Quality
94.9
Maintenance
100
Vulnerability
100
License
Total Downloads
2,332
Last Day
10
Last Week
205
Last Month
1,511
Last Year
2,332
Minified
Minified + Gzipped
Latest Version
1.0.11
Package Id
@cleanweb/react@1.0.11
Unpacked Size
43.68 kB
Size
11.82 kB
File Count
22
NPM Version
10.8.2
Node Version
20.17.0
Publised On
23 Oct 2024
Cumulative downloads
Total Downloads
Last day
-90.7%
10
Compared to previous day
Last week
72.3%
205
Compared to previous week
Last month
3,114.9%
1,511
Compared to previous month
Last year
0%
2,332
Compared to previous year
1
6
This package provides a suite of tools for writing cleaner React function components. It is particularly useful for larger components with lots of state variables and multiple closure functions that need to access those variables. The most likely use cases will use one of the two main exported members.
The useLogic
allows you to write your component's logic outside the function component's body, and helps you keep them all better organized. It also provides a much cleaner API for working with multiple state variables. Here's what a function component looks like with the useLogic
hook.
Before
1const Button = (props) => { 2 const { param } = props; 3 4 const [state1, setState1] = useState(); 5 const [state2, setState2] = useState(); 6 const [label, setLabel] = useState('Click me'); 7 const [submitted, setSubmitted] = useState(false); 8 9 const memoizedValue = useMemo(() => getValue(param), [param]); 10 11 const subscribeToExternalDataSource = useCallback(() => { 12 externalDataSource.subscribe((data) => { 13 setLabel(data.label); 14 }); 15 }, [setLabel]); 16 17 useEffect(subscribeToExternalDataSource, []); 18 19 const submit = useCallback(() => { 20 sendData(state1, state2); 21 setSubmitted(true); 22 }, [state1]); // Notice how `state2` above could easily be stale by the time the callback runs. 23 24 return <> 25 <p>{memoizedValue}</p> 26 <button onClick={submit}> 27 {label} 28 </button> 29 </>; 30}
After
1class ButtonLogic { 2 static getInitialState = () => { 3 return { 4 state1: undefined, 5 state2: null, 6 label: 'Click me', 7 submitted: false, 8 }; 9 } 10 11 submit = () => { 12 const { state1, state2 } = this.state; 13 sendData(state1, state2); 14 this.state.submitted = true; 15 } 16 17 subscribeToExternalDataSource = () => { 18 externalDataSource.subscribe((data) => { 19 this.state.label = data.label; 20 }); 21 } 22 23 useHooks = () => { 24 const { param } = this.props; 25 26 useEffect(this.subscribeToExternalDataSource, []); 27 const memoizedValue = useMemo(() => getValue(param), [param]); 28 29 return { memoizedValue }; 30 } 31} 32 33// Button Template 34const Button = (props) => { 35 const { state, hooks, ...methods } = useLogic(ButtonLogic, props); 36 37 return <> 38 <p>{hooks.memoizedValue}</p> 39 <button onClick={methods.submit}> 40 {state.label} 41 </button> 42 </>; 43}
The useLogic
hook combines the functionality of two base hooks which can also be used directly. They are useCleanState
and useMethods
. useCleanState
can be used independently if you only want a cleaner state management API. useMethods
is designed to be used together with useCleanState
, but rather than calling both individually, you may find it more convenient to use useLogic
, which combines both and also adds additional functionality.
It is possible to have multiple calls to
useLogic
in the same component. This allows your function component template to consume state and logic from multiple sources, or it can simply be used to group distinct pieces of related logic into separate classes.
For a fuller discussion of how useLogic
works, start at the clean-state documentation.
For an API reference, see the API reference.
In addition to having cleaner and more structured component logic, you can also simplify the process of working with your component's lifecycle with the final two exported members. The useInstance
hook builds on the functionality of useLogic
and adds lifecyle methods to the class. This means the class can now be thought of as truly representing a single instance of a React component. The ClassComponent
class extends this to its fullest by allowing you to write the function component itself as a method within the class, and removing the need to explicitly call useInstance
.
Before
1const Button = (props) => { 2 const [state1, setState1] = useState(props.defaultValue); 3 const [state2, setState2] = useState(); 4 const [label, setLabel] = useState('Click me'); 5 const [submitted, setSubmitted] = useState(false); 6 const [store, updateStore] = useGlobalStore(); 7 8 // Required to run once *before* the component mounts. 9 const memoizedValue = useMemo(() => getValue(), []); 10 11 // Required to run once *after* the component mounts. 12 useEffect(() => { 13 const unsubscribe = externalDataSource.subscribe((data) => { 14 setLabel(data.label); 15 }); 16 17 const onWindowResize = () => {}; 18 19 window.addEventListener('resize', onWindowResize); 20 21 return () => { 22 unsubscribe(); 23 window.removeEventListener('resize', onWindowResize); 24 }; 25 }, []); 26 27 // Run *after* every render. 28 useEffect(() => { 29 doSomething(); 30 return () => {}; 31 }) 32 33 const submit = useCallback(() => { 34 sendData(state1, state2); 35 setSubmitted(true); 36 }, [state1]); 37 38 // Run before every render. 39 const text = `${label}, please.`; 40 41 return <> 42 {memoizedValue ? memoizedValue.map((copy) => ( 43 <p>{copy}</p> 44 )) : null} 45 <button onClick={submit}> 46 {text} 47 </button> 48 </>; 49} 50 51export default Button;
After
1class Button extends ClassComponent { 2 static getInitialState = (props) => { 3 return { 4 state1: props.defaultValue, 5 state2: null, 6 label: 'Click me', 7 submitted: false, 8 }; 9 } 10 11 useHooks = () => { 12 const [store, updateStore] = useGlobalStore(); 13 return { store, updateStore }; 14 } 15 16 /*************************** 17 * New Lifecycle Methods * 18 ***************************/ 19 20 beforeMount = () => { 21 this.memoizedValue = getValue(); 22 } 23 24 // Run after the component is mounted. 25 onMount = () => { 26 const unsubscribe = this.subscribeToExternalDataSource(); 27 window.addEventListener('resize', this.onWindowResize); 28 29 // Return cleanup callback. 30 return () => { 31 unsubscribe(); 32 window.removeEventListener('resize', this.onWindowResize); 33 }; 34 } 35 36 beforeRender = () => { 37 this.text = `${label}, please.`; 38 } 39 40 // Run after every render. 41 onRender = () => { 42 doSomething(); 43 44 // Return cleanup callback. 45 return () => {}; 46 } 47 48 cleanUp = () => { 49 // Run some non-mount-related cleanup when the component dismounts. 50 // onMount (and onRender) returns its own cleanup function. 51 } 52 53 /*************************** 54 * [End] Lifecycle Methods * 55 ***************************/ 56 57 submit = () => { 58 // Methods are guaranteed to have access to the most recent state values, 59 // without any delicate hoops to jump through. 60 const { state1, state2 } = this.state; 61 62 sendData(state1, state2); 63 64 // CleanState uses JavaScript's getters and setters, allowing you to assign state values directly. 65 // The effect is the same as if you called the setter function, which is available through `state.put.submitted(true)`. 66 this.state.submitted = true; 67 } 68 69 onWindowResize = () => { 70 ; 71 } 72 73 subscribeToExternalDataSource = () => { 74 const unsubscribe = externalDataSource.subscribe((data) => { 75 this.state.label = data.label; 76 }); 77 78 return unsubscribe; 79 } 80 81 /** You can also separate out discreet chunks of your UI template. */ 82 Paragraphs = () => { 83 if (!this.memoizedValue) return null; 84 85 return this.memoizedValue.map((content, index) => ( 86 <p key={index}> 87 {content || this.state.label} 88 </p> 89 )); 90 } 91 92 /** Button Template */ 93 Render = () => { 94 const { Paragraphs, submit, state } = this; 95 96 return <> 97 <Paragraphs /> 98 99 {/* You can access the setter functions returned from useState through the state.put object. */} 100 {/* This is more convenient than the assignment approach if you need to pass a setter as a callback. */} 101 {/* Use state.putMany to set multiple values at once. It works just like setState in React.Component classes. */} 102 {/* e.g state.inputValue = 'foo', or state.put.inputValue('foo'), or state.putMany({ inputValue: 'foo' }) */} 103 <CustomInput setValue={state.put.inputValue}> 104 105 <button onClick={submit}> 106 {this.text} 107 </button> 108 </>; 109 } 110} 111 112// Call the static method FC() to get a function component that you can render like any other function component. 113export default Button.FC();
If you would like to keep the actual function component separate and call
useInstance
directly, see theuseInstance
docs for more details and examples.
At its core, any component you write with ClassComponent
is still just a React function component, with some supporting logic around it. This has the added advantage of making it significantly easier to migrate class components written with React.Component
to the newer hooks-based function components, while still maintaining the overall structure of a class component, and the advantages that the class component approach provided.
For a fuller discussion of how this works, start at the useInstance
documentation.
For more details on the lifecycle methods and other API reference, see the ClassComponent
API docs.
<Use>
ComponentIf you only want to use hooks in your React.Component
class without having to refactor anything, use the Use
component.
1class Button extends React.Component { 2 handleGlobalStore = ([store, updateStore]) => { 3 this.setState({ userId: store.userId }); 4 this.store = store; 5 this.updateStore = updateStore; 6 } 7 8 UseHooks = () => { 9 return <> 10 <Use hook={useGlobalStore} 11 onUpdate={handleGlobalStore} 12 argumentsList={[]} 13 key="useGlobalStore" 14 /> 15 </>; 16 } 17 18 render() { 19 const { UseHooks } = this; 20 21 return <> 22 <UseHooks /> 23 24 <button>Click me</button> 25 </>; 26 } 27}
No vulnerabilities found.
No security vulnerabilities found.