@anissoft/react-helpers v2.4.1
React Helpers
Just bunch of helpers and hooks, that I commonly use in my code
Installation
Just run npm install
command:
$ npm install @anissoft/react-helpers
Components:
- \<If condition />
Conditional render in jsx format
import * as React from 'react';
import { render } from 'react-dom';
import { If, Then, Else } from '@anissoft/react-helpers/components/If'
import MainApp from 'Components/Main';
import Error from 'Components/Error';
...
render(
<div>
<If condition={!isErrored}>
<Then><MainApp/></Then>
<Else><Error/></Else>
</If>
</div>,
document.getElementById('app-root'),
);
also, there is a shortener for case without else:
<div>
<If condition={!isErrored}>
<MainApp />
</If>
</div>
Then and Else can receive a callbacks as children - that allows you to safely use inside them methods, props and variables
<div>
<If condition={!!foo} >
<Then>{() => <p>{`Here some value for you ${foo.bar()}`}</p>}</Then>
</If>
</div>
}
- \<Memo deps>
Update it's children only if deps was changed
import * as React from 'react';
import { render } from 'react-dom';
import Memo from '@anissoft/react-helpers/components/Memo'
...
const Example = () => {
const [state1, setState1] = React.useState(0);
const [state2, setState2] = React.useState(0);
React.useEffect(
() => {
const interval = setInterval(() => {
setState2(old => old + 1);
}, 100);
return () => {
clearInterval(interval);
};
},
[],
);
return (
<div>
<Memo deps={[state1]}>
<span>
{state2}
</span>
<span>This value doesn't change, until you press </span>
<button role="button" onClick={() => setState1(v => v + 1)}>Increment</button>
</Memo>
</div>
);
};
- \<Wrapper condition />
Conditional render like in < If />, but this time for wrapping components
import * as React from 'react';
import { render } from 'react-dom';
import { Wrapper } from '@anissoft/react-helpers/components/Wrapper'
import MainApp from 'Components/Main';
import MobleViewWrapper from 'Components/Mobile';
...
render(
<div>
<Wrapper condition={isMobile} wrapper={MobleViewWrapper}>
<MainApp/>
</Wrapper>
</div>,
document.getElementById('app-root'),
);
also, can be used with function wrap
as wrapper
import * as React from 'react';
import { render } from 'react-dom';
import { Wrapper } from '@anissoft/react-helpers/components/Wrapper'
import MainApp from 'Components/Main';
import MobleViewWrapper from 'Components/Mobile';
...
const wrapIn = (children) => {
...
return <MobleViewWrapper>{children}</MobleViewWrapper>
}
render(
<div>
<Wrapper condition={isMobile} wrap={wrapIn}>
<MainApp/>
</Wrapper>
</div>,
document.getElementById('app-root'),
);
- \
Conditional render, but for several conditions. Simple implementation of javascript switch
import * as React from 'react';
import { render } from 'react-dom';
import { Switch, Case, Default } from '@anissoft/react-helpers/components/Switch'
import AdminView from 'Components/Admin';
import UserView from 'Components/User';
import DefaultView from 'Components/Default';
...
render(
<div>
<Switch>
<Case condition={ userRole === 'admin' }>
<AdminView />
</Case>
<Case condition={ userRole === 'regular' }>
<UserView />
</Case>
<Default>
<DefaultView />
</Default>
</Switch>
</div>,
document.getElementById('app-root'),
);
Can render several positive cases
render(
<div>
<Switch>
<Case condition={userRoles.includes('admin')}>
<AdminView />
</Case>
<Case condition={userRole.includes('regular')}>
<UserView />
</Case>
<Default>
<DefaultView />
</Default>
</Switch>
</div>,
document.getElementById('app-root')
)
- \<Try onCatch, silent>
A react error boundarie component, for catching errors from its own children
import * as React from 'react';
import { render } from 'react-dom';
import Try from '@anissoft/react-helpers/components/Try'
...
const ErrorComponent = ({ shouldThrow }: { shouldThrow?: boolean }) => {
if (shouldThrow) {
throw new Error('💣');
} else {
return null;
}
}
const Example = () => {
return (
<div>
<Try onCatch={(error: Error) => <p>Smth went wrong</p>}>
<ErrorComponent shouldThrow/>
</Try>
</div>
)
};
- \<Freeze enabled>
Stops re-render its children if enabled = true
import * as React from 'react';
import { render } from 'react-dom';
import Freeze from '@anissoft/react-helpers/components/Freeze'
...
const Example = () => {
const [state, setState] = React.useState(0);
React.useEffect(
() => {
setInterval(() => setState(old => old + 1), 1000);
},
[],
);
return (
<div>
<Freeze enabled={state >= 10}>
<span>Will update this number, until it became 10 - [{state}]</span>
</Freeze>
</div>
)
};
- \<EventProxy direction>
Just render this component inside DOM, set direction to target DOM element and track any of these events on that element.
- onResize
- onMutation
- onScroll
- onClick
- onClickCapture
- onFocus
- onBlur
- onMouseOver
- onMouseOut
import * as React from 'react';
import { render } from 'react-dom';
import EventProxy from '@anissoft/react-helpers/components/EventProxy'
...
const Example = () => {
return (
<div>
<EventProxy
direction="child"
component="i"
onResize={(event) => console.log('resize', event)}
onMutation={(event) => console.log('mutation', event)}
onScroll={(event) => console.log('scroll', event)}
onBlur={(event) => console.log('blur', event)}
onFocus={(event) => console.log('focus', event)}
onClick={(event) => console.log('click', event)}
onClickCapture={(event) => console.log('click-capture', event)}
onMouseOver={(event) => console.log('hover', event)}
onMouseOut={(event) => console.log('mouseout', event)}
>
<span>Target child</span>
</EventProxy>
</div>
)
};
You can pass onEvent=true, if you want just rerender your component
Note that you can create an infinity loop of rerender, if you content depends on element size
export default () => {
return (
<div>
<EventProxy direction="parent" onResize />
My width: {node.offsetWidth} and height: {node.offsetHeight}
</div>
)
}
Also, you can specify path to target component with query selector string.
export default () => {
return (
<div>
<EventProxy direction="span > .class" onClick={() => console.log('Gotcha')}>
<UnbelievableStupidComponent />
</EventProxy>
</div>
)
}
- \<Countdown enabled>
Return coundown in minutes or/and seconds. Supports locales "en"
and "ru"
import * as React from 'react';
import { render } from 'react-dom';
import Countdown from '@anissoft/react-helpers/components/Countdown'
...
const Example = () => {
return (
<div>
You have <Countdown seconds={120} format="mm ss"/> left
</div>
)
};
Hooks
- useRouter()
React hook, which allows you to use match
, location
and history
from React-Router. Should be used in components under \, \ etc.
import * as React from 'react';
import useRouter from '@anissoft/react-helpers/hooks/useRouter';
export default () => {
const {match, location, history} = useRouter();
return (
<div>
<p>Current route path: <b>{match.path}</b></p>
<p>Whole pathname of page: <b>{location.pathname}</b></p>
<input
type="button"
onCLick={() => history.push(`${match.path}/directory`)}
>
Add directory
</>
</div>
);
}
- useDebounced(value, delay)
Debounce the value for delay (in ms)
import * as React from 'react'
import useDebounced from '@anissoft/react-helpers/hooks/useDebounced'
export default ({ initial }) => {
const [value, setValue] = useState(initial)
const [debouncedValue, setDebouncedValue] = useDebounced(initial, 300)
const handleChange = e => {
setValue(e.target.value)
setDebouncedValue(e.target.value)
}
return (
<div>
<input onChange={handleChange} />
<p>Value: {value}</p>
<p>DebouncedValue: {debouncedValue}</p>
</div>
)
}
- useThrottled(value, delay)
Throttle the value for delay (in ms)
import * as React from 'react'
import useThrottled from '@anissoft/react-helpers/hooks/useThrottled'
export default ({ initial }) => {
const [value, setValue] = useState(initial)
const [throttledValue, setThrottledValue] = useThrottled(initial, 300)
const handleChange = e => {
setValue(e.target.value)
setThrottledValue(e.target.value)
}
return (
<div>
<input onChange={handleChange} />
<p>Value: {value}</p>
<p>ThrottledValue: {throttledValue}</p>
</div>
)
}
- useMounted()
Shortway for 'didMount' property
import * as React from 'react'
import If from '@anissoft/react-helpers/components/If'
import useMounted from '@anissoft/react-helpers/hooks/useMounted'
export default () => {
const [mounted] = useMounted()
return (
<div>
<If
condition={mounted}
then={() => <p>Component just renders</p>}
else={() => <p>Component was rendered before</p>}
/>
</div>
)
}
Since version 2.4.0 useMounted returns current state and function - that allows you to use it in async effects to check, if component still mounted and prevent memory leak
export default () => {
const [mounted, isMounted] = useMounted()
const [state, setState] = React.useState(0)
React.useEffect(() => {
fetch('/some/api').then(res => {
if (isMounted()) {
setState(res.ok)
}
})
}, [])
return <div>💣</div>
}
- useRefFor(React.Component)
Returns enhanced component and ref for it;
import * as React from 'react'
import useRefFor from '@anissoft/react-helpers/hooks/useRefFor'
import CustomInput from 'Components/MyInput'
export default () => {
const [ref, Input] = useRefFor(CustomInput)
React.useEffect(() => {
console.log('Value in input was changed since last render')
}, [ref.current.value])
return (
<div>
<Input />
</div>
)
}
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago