easy-peasy icon indicating copy to clipboard operation
easy-peasy copied to clipboard

useStoreState doesn't react to changes in the state after Fast Refresh in React Native

Open sansiaali opened this issue 6 years ago • 11 comments

Hi,

I added easy-peasy(v.3.3.0) successfully into a new React Native(v0.62.2) project but noticed that a function component using useStoreState will not react to the state after editing the component code. My button will send a request, receive a new picture of a dog and set that dog into the state but my component will not detect the state change. I have React Native's Fast Reload enabled.

Here is my test component (TestComponent.tsx):

import ...

export function TestComponent() {
  const dog = useStoreState((state) => state.test.dog);
  const getDog = useStoreActions((actions) => actions.test.getDog);

  const handleGetDogPress = useCallback(async () => {
    try {
      await getDog();
    } catch {
      console.log('Simulated api error occurred');
    }
  }, [getDog]);

  return (
    <View style={styles.container}>
      {dog && <Image style={styles.logo} source={{uri: dog}} />}
      <Button title="Get Dog" onPress={handleGetDogPress} />
    </View>
  );
}

const styles = StyleSheet.create(...)

Fast Refresh documentation points out that it'll try to preserve the state if a change is done to a file that only exports a React component:

When possible, Fast Refresh attempts to preserve the state of your component between edits. In particular, useState and useRef preserve their previous values as long as you don't change their arguments or the order of the Hook calls.

If I change the order of the useStoreState and useStoreActions, the useStoreState hook will work until I make a modification that makes Fast Refresh try to preserve values of useStates and useRefs. Putting // @refresh reset somewhere in the file also works but it forces the component to re-render on every save. Disabling Fast Refresh works as well but it makes the developer experience really bad.

Maybe the bug is related to the useRef hooks used in the useStoreState? I checked the code but I'm afraid I don't know enough about hooks/redux/easy-peasy yet to fix it myself.

Is there anyone that can look into this?

sansiaali avatar Apr 17 '20 23:04 sansiaali

Hi @shancial

Thanks for this report. I can empathise with that pain. I'll def make some time to look into this for you.

ctrlplusb avatar Apr 18 '20 00:04 ctrlplusb

Thanks!

I can provide you with the test project code that I tested this with, but I basically used the official guide (npx react-native init AwesomeTSProject --template react-native-template-typescript) to set up a base and added easy-peasy with a property, setter and a thunk.

sansiaali avatar Apr 18 '20 11:04 sansiaali

same issue.

Nr9 avatar May 05 '20 06:05 Nr9

It seems like Fast Refresh / react-refresh is also coming to create-react-app in the future.

sansiaali avatar May 05 '20 06:05 sansiaali

Can also confirm this is happening to me as well. Anything I can do that would help with getting this looked into? :)

DaneEveritt avatar Jul 24 '20 16:07 DaneEveritt

Hi all, I want to look into this. Are you all running the Expo CLI, and RN Web?

ctrlplusb avatar Oct 08 '20 09:10 ctrlplusb

I am using the standard react-native CLI and React Native.

DaneEveritt avatar Oct 08 '20 17:10 DaneEveritt

Are you all running the Expo CLI, and RN Web?

Next.js and CRA. Both are also facing this issue. You can find a small reproduction repo based on CRA here.

It's stripped down to only containing a counter and a button for incrementing the counter.

Changing the component makes the counter stop updating when clicking the button. According to the Redux DevTools the store state keeps updating on click. Changing the component again without refreshing the page updates the counter once to the current store value, but the counter still does not update when clicking the button.

Changing the store logic (like changing the incrementing value) makes the refresh break completely. No changes on the component are reflected on the website anymore. Instead the counter keeps updating on every click, unfortunately it updates based on the old incrementing value. I am not sure if that is the same issue or a different one, though.

rfermann avatar Oct 30 '20 15:10 rfermann

I confirm the same as @rfermann issue is happening with nextjs.

hutber avatar Nov 01 '20 17:11 hutber

I just ran into this too building an app that uses Fast Refresh, but for the web, and not with React Native.

Edit: After an HMR update, the actions are definitely continue to fire based on adding console.debug statements to the function.

It seems like the type of state update may be involved. If I push onto an array even after a hot update, the state continues to update fine and components on screen will refresh as expected. However, if I modify the array with a splice to delete an item, then the components do not refresh (yet the change is applied to the state because I am using localStorage persistence).

Edit 2: I also see that performing an behavior (i.e. button click) which modifies local state with a useState() hook causes all components to refresh once (including those using state from EP), but the action handlers that delete an item with a .splice() continue to not trigger a refresh. Very odd.

mrapczynski avatar Dec 02 '20 18:12 mrapczynski

We're also starting to see the issue of fast refresh not working properly with easy-peasy. I've reproduced the issue in this codesandbox:

chrome_NVK65pZfLX

Any ideas as to what is causing this @ctrlplusb ?

jmyrland avatar Jan 12 '22 12:01 jmyrland

Fixed in v5.1.0 🎉

ctrlplusb avatar Sep 17 '22 04:09 ctrlplusb