Explanation:
When not using useDistinct, every call to setState will rerender the component. Even if you call setState(state).
When using useDistinct, it should check for === equality. Or you can provide a custom comparison function which does the equality check.
As cancelAnimationFrame method is executed in the clean-up period, the animation ID "stored" in raf can be perfectly cancelled. However, the onFrame method may continues (especially when the main thread render DOM slowly, and it will take sometime between useEffect doing cleaning work and your requestAnimationFrame method's running, https://github.com/streamich/react-use/blob/master/src/useRaf.ts#L9 ), so that a new raf will be assigned, even though you already canvel previous raf.
In this way, you don't clean up previous animation, and next effect will bring in a new animation, which is the problem.
In my opinion, a safe way to guarantee current animation's stop is to add conditions in your main loop method, onFrame method can be rewrited to:
And now we have useAsync, but it can only act as Query.
We should have an useApi to act as Mutation.
// A very very naive implementationconstuseApi=(promisified_api,variables)=>{const[state,set_state]=useState({loading: !!variables});constapi=async(...variables)=>{set_state({loading:true});constdata=awaitpromisified_api(...variables);set_state({data});}// we should expose `set_state`, it can act as Query's updteQuery, and use can set_state({error:null}) manually when close the error dialog.return[api,state,set_state];}const[api,state,set_state]=useApi(fn_return_promise,maybe_variables);
This issue is just to note that useLocation will break on IE11 without a polyfill for window.Event. even when <meta http-equiv="x-ua-compatible" content="IE=edge"> is already in head.
IE9, 10 and 11 will break right here when new Event('pushstate'); is run by calling history.push('/something') in your react app.
You need to polyfill window.Event which import '@babel/polyfill'; is not doing for you. So here goes what I've added to my polyfill.js
/** * To detect you are in IE (for this case) by checking typeof(Event) which is * 'function' for all except IE where it is 'object'. * You can then safely polyfill the Event constructor using the approach above. * In IE11 it seems to be safe to set window.Event = CustomEvent. */(function(){if(typeofwindow.Event==='function')returnfalse;//If not IEfunctionCustomEvent(event,params){params=params||{bubbles: false,cancelable: false,detail: undefined,};varevt=document.createEvent('CustomEvent');evt.initCustomEvent(event,params.bubbles,params.cancelable,params.detail);returnevt;}CustomEvent.prototype=window.Event.prototype;window.Event=CustomEvent;})();
I tried to use the package on next.js and it throws the following error:
Error: Addon "cssom" is missing the following dependencies:
require("nano-css/addon/sh").addon(nano);
at warnOnMissingDependencies (/Users/rafael/Code/blumpa-ssr/node_modules/nano-css/addon/__dev__/warnOnMissingDependencies.js:23:15)
at exports.addon (/Users/rafael/Code/blumpa-ssr/node_modules/nano-css/addon/cssom.js:5:55)
at Object.<anonymous> (/Users/rafael/Code/blumpa-ssr/node_modules/react-use/lib/useCss.js:27:1)
at Module._compile (module.js:653:30)
at Object.Module._extensions..js (module.js:664:10)
at Module.load (module.js:566:32)
at tryModuleLoad (module.js:506:12)
at Function.Module._load (module.js:498:3)
at Module.require (module.js:597:17)
at require (internal/module.js:11:18)
at Object.<anonymous> (/Users/rafael/Code/blumpa-ssr/node_modules/react-use/lib/index.js:17:18)
at Module._compile (module.js:653:30)
at Object.Module._extensions..js (module.js:664:10)
at Module.load (module.js:566:32)
at tryModuleLoad (module.js:506:12)
at Function.Module._load (module.js:498:3)
Iβve enabled the strict option in my tsconfig.json, and installing this package results in an error because it canβt find types for the useCallbag hook, even though I donβt use that hook. It seems to be trying to import the types for the use-callbag package, which donβt exist. Can you fix this error?
Explicitly defining the licence will ensure there are no future developer concerns about whether or not this module is for them. May I suggest a permissive license such as MIT or Apache?
Hook that creates a dispatcher for errors, that can be caught with error boundaries.
constuseError=()=>{const[err,raise]=useState();if(err){throwerr;}returnraise;};constDemo=()=>{constraise=useError();useEffect(()=>{setTimeout(()=>{raise(newError("Could not work with setTimeout for some reason!"));},1000);});return<div>Hello world</div>;};
Alternative names: useError, useRaise, useThrow, useErrorDispatch.
@streamich I think it's good idea to put EditorConfig in this project to make sure all contributors have the same configuration and prevent unnecessary the code formatting change over each PR.
π¨ The automated release from the master branch failed. π¨
I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.
You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. Iβm sure you can resolve this πͺ.
Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.
Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.
If you are not sure how to resolve this, here is some links that can help you:
If those donβt help, or if this issue is reporting something you think isnβt right, you can always ask the humans behind semantic-release.
Invalid npm token.
The npm token configured in the NPM_TOKEN environment variable must be a valid token allowing to publish to the registry https://registry.npmjs.org/.
If you are using Two-Factor Authentication, make configure the auth-onlylevel is supported. semantic-release cannot publish with the default auth-and-writes level.
Please make sure to set the NPM_TOKEN environment variable in your CI with the exact value of the npm token.
Some of my pages and components use use-css to style, but when I switched to them, them would always twinkle at first, without styles and become normal in the next flash.
since after the first callοΌstate.loading was set to false in useEffect.After then state.loading would still be false in the second call for refetching.
so maybe state should be reset in useEffect:
react_1.useEffect(
() => {
let mounted = true;
set({ loading: true }); // reset state
const promise = memoized();
promise.then(
value => {
if (mounted) {
set({
loading: false,
value
});
}
},
error => {
if (mounted) {
set({
loading: false,
error
});
}
}
);
return () => {
mounted = false;
};
},
[memoized]
);
This library minified is almost 52kb, which is huge for what it is. 60% of the bundle size is solely based on dependencies, all of which are only used in a few hook.
I would suggest making turning those into peerDependencies and requiring users to include the libraries in their own package.json. This would make the size of this library ~21kB.
Although tree shaking should take care of this, not all environments support it, and forcing dependencies on users isn't the best course of action, especially if it's for a small functionality.
If this is a go, I could make the PR with the changes (code & docs) required for this.
Saw that you already got use-styles on npm, but couldn't find anything on GitHub.
Are you actively working on something? Would be keen to share experiences, since I have been working on something very similar: https://github.com/andywer/react-usestyles
importuseDebouncefrom'./path/to/useDebounce'functionComponent(){constdebounce=useDebounce()functionhandleClick(event: React.ChangeEvent<HTMLInputElement>){console.log('Clicked with debounce')}return<inputtype="text"onChange={debounce(handleClick)}/>}
It works fine, as long as the state changes. But it won't trigger when I pass equal state with a new delay to updateState.
What it's intended to do:
store a whole object
some state changes should be debounced (for example search query input). So here I'd use setState({...state, query: ''}, 300).
other state changes should trigger immediately (for example click on the search button, or clicking a checkbox). And here: setState(state, 0) or setState({...state, checkbox: true}, 0).
state is the current state, which can be used as value for input fields
debouncedState can be used with useEffect to detect, when to trigger an action (for example execute API request)
Test code:
const[state,debouncedState,setState]=useDebouncedState("foo");useEffect(()=>{consts="bar";setTimeout(()=>{setState(s,5000);},0);setTimeout(()=>{setState(s,0);// this won't do anything, because only delay changed},1000);},[])
This prevents rerender, when using zero (or negative) delay.
Btw: Is there any need for using bind instead of simply fn(args)?
EDIT 2: Here's what all my changes look like:
constuseDebounce=(fn: ()=>any,ms: number=0,args: Array<any>=[])=>{const[timeout,setTimeoutVar]=useState<any>(null);useEffect(()=>{// if args change then clear timeoutclearTimeout(timeout);if(ms<1){// optimization for zero-delayfn.bind(null,args)();}else{constt=setTimeout(fn.bind(null,args),ms);setTimeoutVar(t);}},[ms, ...args]);// here I added `ms`};
EDIT 3: Another optimization would be to remove const [timeout, setTimeoutVar]. Because setTimeoutVar(t); will trigger a rerender, too.
My tests showed that this code for useDebounce rerenders less:
constuseDebounce=(fn: ()=>any,ms: number=0,args: Array<any>=[])=>{useEffect(()=>{// if args change then clear timeoutlett: any;if(ms<1){fn.bind(null,args)();}else{t=setTimeout(fn.bind(null,args),ms);}return()=>{// use this callback for clearTimeout, it has beenclearTimeout(t);// suggested by Dan Abramov himself:}// https://twitter.com/dan_abramov/status/1060729512227467264},[ms, ...args]);};
Though I'm not sure if it's breaking change? But it seems to works fine.
EDIT 4: Forget (nearly) everything I said π
It looks like setTimeoutVar(t); is the only real problem that causes unnecessary rerenders!
So... This code seems to work fine in combination with useDebounce(() => ..., delay, [state, delay]):
constuseDebounce=(fn: ()=>any,ms: number=0,args: Array<any>=[])=>{useEffect(()=>{lethandle=setTimeout(fn.bind(null,args),ms);return()=>{// if args change then clear timeoutclearTimeout(handle);}},args);};
Just copy-paste useLocalStorage and s/local/session
In useLocalStorage.ts, add a parameter called storageKey that defaults to 'localStorage' and have useSessionStorage just call that. Then in useLocalStorage, s/localStorage/window[storageKey]
First of all, thank you for this package, it has been very useful for my projects!
I've noticed the production build it's not fully compatible with IE11.
I managed to do a "manual tree-shake" using babel-plugin-transform-imports, but i still get errors on IE11 using some hooks, e.g:
// ...// production build of useWindowSize, IE11 won't be able to destructure thisconst[state,setState]=react_1.useState({width: isClient ? window.innerWidth : initialWidth,height: isClient ? window.innerHeight : initialHeight,});// ...
My question is: can we add a .browserslistrc on the package, so we can get full support for older browsers in the production build?
Translation file is plain object, which values are strings or functions returning strings or even JSX markup.
Then we create React Context for locale LocaleContext = React.createContext() and new hook named useTranslate. It loads translations file on every context change and returns translation function to a component.
As ES6 template tag it extracts key and arguments from passed template, and also returns raw ES6 template value as fallback if key is not found in translations object.
As regular function it uses first argument for key lookup and passes rest arguments to translation template.
Benefits:
We can localize each component independently.
Or we can create common resources and utilities and import them in each component translations file.
Or we can group translations in other ways.
Implementation can be found here: gist (about 100 SLOC).
If this is interesting, I can submit a PR.