Reducers listen for actions of a certain type and then update the store as needed, but should you use an action without changing the store?
Maybe on route changes or on button clicks so that what the user does shows up in timemachine, or is this abusing actions?
Actions are linked to reducers through their 'type', in general actions should be linked with at least one reducer.
It seems like you can achieve the functionality you are looking for by creating a function inside your component that is your method called by the onClick, submit, or whatever activity happens, something like this:
myOnCLickMethod(passedInfo){
const {dispatch} = this.props
//any JavaScript code you need
dispatch(myAction(passedInfo))
}
This ensures you can do anything you want that doesn't touch the state while still allowing for actions to fire and state changes when that activity happens.
An action is a call for state change. So if route changes or button clicks don't change the state of your app, you shouldn't use actions for them. Maybe log is more relevant in this scenario.
Related
So I am learning NGRX and I am close to understanding how it works, I am dispatching events and I can see them in store-devtools chrome extension.
What I want to know is how can I save a state and apply it after? My purpose is to save a state from a specific page so that when I'm back to that page I will apply the old state and I will not lose my work there
Here's my repo: https://bitbucket.org/wmoreiradev/ngrxonfire/src/effects-refactor/
You can do this like bellow
Create actions to save and load current state.
Save the current state before leaving the page. You can do this inside the reducer function or inside a effect like bellow
localStorage.setItem("currentState", JSON.strigify(state));
When you load the page dispatch an action to load the saved state inside a reducer
case Actions.LOAD_SAVED_STATE:
return {...state, ...action.payload};
also, remove the save state from localStorage.
When dispatching several different actions for one reducer, only the last one triggers component update. It might be better to show then explain.
Some notes on provided example:
App component reflects a history of updates of it's prop redirectPath. When it comes as null then no redirect string adds to history.
There is a reducer which returns just a plain string or null depending on action.
By pressing a button Do redirect I expect both actions (SET_REDIRECT and CLEAR_REDIRECT) provide changed state to AppContainer component. But only the latest one (CLEAR_REDIRECT) triggers render method with null value.
If we add slight delay between dispatching these actions, then both of them trigger component's render. You can check it by pressing Do redirect with delay button.
I expect both changes (provided by SET_REDIRECT and CLEAR_REDIRECT actions) in state should trigger component update without using setTimeout when dispatching actions.
I also tried to move dispatching of CLEAR_REDIRECT from middleware, after it gets SET_REDIRECT, but the same result.
Can I somehow reach expected behaviour?
Initially I posted the issues to redux repo, because I thought it's an issue in redux, but #jimbolla explained me that it's mostly by design of react.
Here is the reference to the original issues and comments from redux team member https://github.com/reactjs/redux/issues/2532.
Don't ever rely on performing state updates in render(). The only code that should be executed in render() is the code required to construct the view.
You could use componentWillReceiveProps to track when your component receives new properties.
You should listen for the appropriate property and perform your redirect when received. You should then listened for a property that indicates the redirection was successful and then you can dispatch an action to clear the redirect state if required which will trigger another component update.
i have two fields with redux form. I have a refresh button through which i update my state through an action. This refresh button updates three text values. My problem is that i must refresh the field values of my form. How to update the state of my redux form. I'm thinking of using a selector like this:
export const formsState = state => state.get('form');
Then i will create a reducer which is taking the formstate and updates it with
update formsState
.update('order', action.payload.price);
But i dont think this is the best solution. Do have some better ideas?
Make sure you refresh button send an action which will update your store via the reducer.
In order to update your component I would suggest to use a react containers usinng connect.
Use the following function:
store.getState() to get your state.
store.dispatch() to dispatch your action.
Currently meteor supports a limited number of events that we can react to from our template definitions. I would like a way to react to events beyond this predefined list. I want the freedom to add any event, even custom events, to the list of possible events in a template.
One idea I had would be to set up a jquery event handler somewhere that listens for the unsupported event and have it set a session variable:
$(form).submit( ->
Session.set('formSubmitted', true)
And then use that session variable when rendering a template:
Template.confirmation.submitted = ->
return Session.get('formSubmitted')
<template name="confirmation">
{{#if submitted}}
<!-- do whatever -->
{{/if}}
</template>
But this is just a workaround and doesn't really address the issue. Is there a real Meteor-way of doing this? Is this something I can do with the new Spark implementations?
NOTE: Please ignore the fact that I'm using the submit event here. I know I can just bind a click event to the submit button, but that's beside the point.
NOTE 2: The accepted answer to this question is also just a workaround.
The rendered callback is what I use to do this.
http://docs.meteor.com/#template_rendered
The callback gives you template instance you should use to find the dom elements you need: http://docs.meteor.com/#template_inst
Untested example below ;)
Template.foo.rendered = ->
$(this.find("form")).submit ->
Session.set 'formSubmitted', true
Using a Session variable than to switch the view is a matter of taste I think.
I have an app State stored in the Session, that toggles Templates. Additionally the backbone package is very useful to provide some meaningful urls.
Can I listen to Alert button click between components using AsyncToken?
Basically, I want to have a method that opens an Alert with buttons and have it return an AsyncToken so that other components calling that method can listen for button click.
Example:
var token:AsyncToken=methodThatOpensAlert();
token.addResponder(new mx.rpc.Responder(buttonClick));
What's the way to do that?
Thank you.
You might be able to use an AsyncToken to achieve this but you could also just register for custom events that you dispatch from the pop up, this is a much cleaner method IMO. Really you've got two relatively clean options I can think of. 1 you make your pop-up dispatch events like "okClicked" "cancelClicked" for different button clicks within the pop-up, you create an instance of the pop up and add listeners then call PopUpManager.addPopUp, or else you do PopUpManager.createPopUp and keep a reference to the returned display object (the instance of the pop-up it created) and add your listeners then. 2 you make two properties in the pop up typed as function, you use them as call backs, so when you create the pop-up you set the okClickedFunction and cancelClickedFunction (or whatever your buttons may be) then in the pop-up you put cilck handlers on the buttons, check to see if the appropriate call-back function is set and call it if so, like
if(okClickedFunction)
okClickedFunction();
Let me know if you have a specific need that makes you think you must use the AsyncToken, but from checking out the docs it looks as though it's strictly meant to work with the other RPC methods and lots of properties are read-only.
EDIT:
[SomeUtilClass.as]
private static function methodThatOpensAlert():CustomAlert
{
return PopUpManager.createPopUp(Application.application, CustomAlert) as CustomAlert;
}
[CustomAlert.as]
[Event(type="flash.events.Event", name="button1Clicked")]
[Event(type="flash.events.Event", name="button2Clicked")]
private function button1Clicked_handler(event:MouseEvent):void
{
dispatchEvent(new Event("button1Clicked", true));
}
private function button2Clicked_handler(event:MouseEvent):void
{
dispatchEvent(new Event("button2Clicked", true));
}
[ThingThatUsesAlert]
var ca:CustomAlert = SomeUtilClass.methodThatOpensAlert();
ca.addEventListener("button1Clicked", button1ClickHandler);
ca.addEventListener("button2Clicked", button2ClickHandler);
And I believe mouse events bubble by default anyhow still so you could really just listen for a click event on the pop up then use the event.target to determine if it was one of the buttons your interested in.
Let me know if you can make sense of this or need more info.