Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating state in child components #42

Open
AlexeyRaga opened this issue Nov 22, 2015 · 7 comments
Open

Updating state in child components #42

AlexeyRaga opened this issue Nov 22, 2015 · 7 comments

Comments

@AlexeyRaga
Copy link

Hi,

I am using the following lens-based approach to propagate a part of the state to the downstream components:

fold
   [ T.focus _items _ListItemAction $ T.foreach \_ -> listItemSpec
   , listActions
   ]

The first component renders a list of items, the second doesn't render anything but defines performAction.

When listItemSpec is updating the state the change is correctly propagated to the parent component through the lens, but the performAction in the second component (listActions) always receives the "old" state, the one "before" changes are applied through the _items lense.

How can a parent component update the state after it has been altered by its children?

Thanks.

@paf31
Copy link
Owner

paf31 commented Nov 22, 2015

The assumption right now is that only one component will handle any action. There is no routing, since the callback you get really just updates the state of the React component.

Maybe the solution is to add some way to getState as well.

@kozak
Copy link

kozak commented Nov 14, 2016

This seems to work in my simple example:newState < T.cotransform id but I have no idea if this is the correct approach.

listActions :: T.Spec _ State _ Action
listActions = T.simpleSpec performAction T.defaultRender
  where
    performAction :: T.PerformAction _ State _ Action
    performAction (ItemAction i Increment) _ oldState = do
      newState <- T.cotransform id
      lift $ liftEff $ log $ "newState: " <> (show newState) <> " oldState: " <> (show oldState)
      pure unit

    performAction _ _ _ = pure unit

I am not sure about the exact order in which the cotransforms will be applied (can this even be guaranteed, if there is an async action in the child for example ?).

One of the use cases where I feel I need this feature, are form components ( each field is a separate component, when the entire form is filled out, additional async validation needs to be performed)

Thank you!

@kozak
Copy link

kozak commented Nov 14, 2016

To answer one of my questions: I've added delays from counter example in the child component:

delay :: Int -> Aff _ Unit
delay ms = later' ms (pure unit)

making it async, so the parent's action will be called after the child's action has finished

@sudhirvkumar
Copy link

sudhirvkumar commented Jan 19, 2017

@kozak We had the exact same issue.

delay is approximate solution and if there is any ajax call involved we will not be able to guarantee that parent's action will be called after the child's action.

The best way is to use the Prism to avoid sending that particular call to the child and handle that particular action in the parent itself, using pattern matching over the child's action!

Child.purs

data Action 
  = Increment
  | Decrement
  | HandleInParent

Parent.purs

data Action 
  = MyAction
  | ChildAction Child.Action

performAction (ChildAction HandleInParent) _ _ = 
  <do stuff>

performAction (ChildAction _ ) _ _ = 
  pure unit

Prism example... the following is not related to the above code... just an example to show how to avoid a particular action from reaching the child spec!

_TaskAction :: Prism' TaskListAction (Tuple Int TaskAction)
_TaskAction = prism (uncurry TaskAction) \ta ->
  case ta of
    TaskAction i HandleInParent -> Left ta
    TaskAction i a -> Right (Tuple i a)
    _ -> Left ta

@paf31 What do you think about this idea? too complex/confusing? can it be simplified?

@kozak
Copy link

kozak commented Jan 19, 2017

@sudhirvkumar If I remember correctly (it has been a while) what I meant by saying that I've added delayis that I've added them to check the async behaviour of child vs parent (not as a workaround, but to check the resulting order of performAction calls in presence of async cotransforms).
The result was that even with async action the parent performAction is called after the child has finished.
That said, what you suggest seems to be in agreement with Paf's statement:

The assumption right now is that only one component will handle any action

and is also intuitive ;)

@sudhirvkumar
Copy link

@kozak Thanks for your quick reply. Do you have any suggestions to improve the code example? or what I have is good enough?

@kozak
Copy link

kozak commented Jan 20, 2017

I am not experienced enough to be able to help you here - but you could probably just ignore the actions you are not interested in (in the child):

performAction _ _ _ = pure unit

Have a look at lines 75-79 : http://try.purescript.org/?gist=f5f273e4c5e4161fceff&backend=thermite

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

No branches or pull requests

4 participants