Skip to content
This repository has been archived by the owner on Nov 10, 2021. It is now read-only.

How to pass values from redux store to useCallback as dependency arguments #36

Closed
AlexanderLoshkarov opened this issue Feb 25, 2019 · 11 comments

Comments

@AlexanderLoshkarov
Copy link

Hi Lads,
Sorry, if this is wrong place to ask the question, please point me to the correct one.
In my case I end up with situation when I have to update my property depend on the changes happened to one of the store values. Was looking through the tutorial and didn't find any solutions for this kind of cases.
After digging a little bit deeper into original redux api I found that I can subscribe to the store directly and getState() outside of useCallback, read the necessary value and provide it as a useCallback dependency argument. But in that case, seems like it makes the useMappedState() redundant...
Could you please help me to find the right way to sort this?

@ianobermiller
Copy link
Contributor

when I have to update my property

What do you mean by this? Are you updating some piece of UI? Or another variable in your component?

@AlexanderLoshkarov
Copy link
Author

@ianobermiller
yes, I'm updating UI.

@AlexanderLoshkarov
Copy link
Author

AlexanderLoshkarov commented Feb 27, 2019

@ianobermiller
here is the simplified code which might clarify my intents

const mapState = useCallback( state => { //...code to read node from the store const value = getValue(node.path)(state); return { value: value, } } ,[ getValue(node.path)(store.getState()) ] );

@AlexanderLoshkarov
Copy link
Author

AlexanderLoshkarov commented Feb 27, 2019

@ianobermiller
in the application I have different inputs as custom components who constantly speaking to the server via persistent connection. So they send their input values and server processes them and respond with validation or calculation results as a commands which then dispatched to the store and updates those values matching their path/key. So I need to react on those values updates coming from the server and dispatched to redux, but I can't because useCallback is limited to the arguments from outside...

In other words I kinda don't understand the situation we limiting to read store updates by the arguments which might not belong to the store at all. I was thinking about the store like an observable collection to which we subscribe for updates receiving, but seems like now it is not.

@AlexanderLoshkarov AlexanderLoshkarov changed the title How to use dependency argument for useCallback from redux store How to use values from redux store to pass them as dependency arguments for useCallback Feb 28, 2019
@AlexanderLoshkarov AlexanderLoshkarov changed the title How to use values from redux store to pass them as dependency arguments for useCallback How to pass values from redux store to useCallback as dependency arguments Feb 28, 2019
@ianobermiller
Copy link
Contributor

Can you create a simple codesandbox demonstrating the issue? Another way to explain this that might help is showing how you would solve this with react-redux.

@AlexanderLoshkarov
Copy link
Author

AlexanderLoshkarov commented Mar 6, 2019

@ianobermiller
Thanks for your response Ian.
I eventually found the work around. But it still looks a little bit weird/awkward to use useState to sort that issue.
Please see updated example. Mostly (Input.tsx)
Edit alex-example

@ianobermiller
Copy link
Contributor

I'm still not really sure what you want to accomplish. Copying from Input.tsx:

  const [localStateValue, setLocalStateValue] = useState("");

  useMappedState(
    useCallback(
      reduxStoreState => {
        const reduxStoreValue = reduxStoreState.processedValue;
        if (localStateValue.value !== reduxStoreValue.value) {
          setLocalStateValue(reduxStoreValue);
        }
      },
      [localStateValue.value] // I wish I can have an access to reduxStoreState.processedValue here
      //to pass it's value as a dependency
    )
  );

useMappedState returns the value you should be using directly, and takes care of not re-rendering if that value hasn't changed. Your code could be as simple as:

  const localStateValue = useMappedState(useCallback(
      reduxStoreState => reduxStoreState.processedValue,
      [],
  ));

@ianobermiller
Copy link
Contributor

How to pass values from redux store to useCallback as dependency arguments

It doesn't really make sense to do this -- the entire point of the callback is to select something from the store, so how could the callback itself be based on the store values? You can certainly select things from the store with useMappedState and then put them in the dependency array of another hook.

I'm going to close right now, but I will reopen if our discussion turns up something actionable.

@AlexanderLoshkarov
Copy link
Author

I'm still not really sure what you want to accomplish. Copying from Input.tsx:

  const [localStateValue, setLocalStateValue] = useState("");

  useMappedState(
    useCallback(
      reduxStoreState => {
        const reduxStoreValue = reduxStoreState.processedValue;
        if (localStateValue.value !== reduxStoreValue.value) {
          setLocalStateValue(reduxStoreValue);
        }
      },
      [localStateValue.value] // I wish I can have an access to reduxStoreState.processedValue here
      //to pass it's value as a dependency
    )
  );

useMappedState returns the value you should be using directly, and takes care of not re-rendering if that value hasn't changed. Your code could be as simple as:

  const localStateValue = useMappedState(useCallback(
      reduxStoreState => reduxStoreState.processedValue,
      [],
  ));

Hi Ian, thanks! Your example is working well, I tried similar thing before, but
seems like there was a bug in my sendbox, the input value was not changing, and I mistakenly thought that this happens because we supply an empty array as a dependency argument to the useCallback.

@AlexanderLoshkarov
Copy link
Author

@ianobermiller
Just want to clarify one last thing, that "connect HOC" from "react-redux" works more precise, because it composes in right direction.
It happens that in our app we remove the parent node from the store to notify the application that edit form must be closed. So in JSX we check if the node does not exist we render null. That makes "react" to remove components tree from the DOM, and because "connect HOC" is a part of that tree it also safely unsubscribes from the store (I hope) , and does not react on store updates coused by parent node removal.
This works differently for hooks. Because hooks do not participate in the components composition (not composed/nested into components tree, like "connect HOC") they're reacting to the store update earlier than components removal happened. That leads to one more redundant cycle and extra problem, like in our case we need to check if the parent exists or make a safer code, just not to get null pointer exception.

I have updated, the previous example, just to clarify that situation.
Please feel free to share your opinion on that!
Is there another way how to eliminate this redundant callback?

@ianobermiller
Copy link
Contributor

Sounds like you may be referring to top-down data flow, which this hook does not implement: https://github.com/facebookincubator/redux-react-hook#how-does-this-compare-to-react-redux

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants