I'm using Redux saga in my React Native app and have a generator function that looks like this:
function* func1(action) {
setInterval(() => {
yield put(ActionCreators.actionCreator1(action));
}, 1000)
}
where ActionCreators is a set of action creators defined elsewhere. This doesn't work, because I'm trying to call the action creator inside the callback of setInterval, which isn't a function generator.
Does anyone know how I can approach this?
Related
I am using react-redux toolkit with redux thunk to make the api calls. In my app, when I dispatch a thunk for update or delete request and after it succession I want to call the get request as well but only way I was able to figure out is by using a flag with useEffect. Is there any better approach you guys can share?
I also tried this piece in my slice file but it won't work as useDispatch cannot be called inside a javascript function block
.addCase(propertiesThunk.deleteProperty.fulfilled, (state, { payload }) => (
useDispatch(propertiesThunk.getProperties())
))
There's a couple problems here.
The first is that you can never call a React hook outside of a function component, so you definitely can't call useDispatch inside of a reducer.
The second problem is that a reducer can never have side effects. That means it can never dispatch actions. A reducer is only for returning an updated state value.
The simplest answer here would be to have an event handler that does both of these steps back-to-back:
function MyComponent() {
const dispatch = useDispatch()
const handleClick = async () => {
await dispatch(someAsyncThunk())
dispatch(someOtherActionHere())
// or some request, or...
}
}
Another option would be to use the new RTK "listener" side effects middleware, and kick off more logic when some action is dispatched:
startListening({
actionCreator: someAsyncThunk.fulfilled,
effect: (action, listenerApi) => {
// do more work here
}
})
See https://redux-toolkit.js.org/api/createListenerMiddleware for details.
This is my first stackoverflow questions please excuse if there is any mistake.
I am a beginner to react, redux and saga.
I am trying to dispatch an action which will be handled by saga and then dispatch another action from within saga. While I do this I get this below error message :
"You can't put (a.k.a. dispatch from saga) frozen actions. We have to
define a special non-enumerable property on those actions for
scheduling purposes. Otherwise you wouldn't be able to communicate
properly between sagas & other subscribers (action ordering would
become far less predictable). If you are using redux and you care
about this behaviour (frozen actions), then you might want to switch
to freezing actions in a middleware rather than in action creator.
Example implementation:
const freezeActions = store => next => action =>
next(Object.freeze(action))"
I haven't explicitly frozen my actions anywhere. I am just calling a function which returns an action object. I dont understand why saga complains that its frozen object.
I have reproduced my error in this sandbox : https://codesandbox.io/s/elastic-zhukovsky-ntmfn
So solution was very simple. When I was trying to import action creator function I was not importing within {}. Action creator was not a default export from where it was defined.
import { setSnackbar } from "../../ducks/snackbar"; //---> senSnackbar should be imported within brackets.
//import setSnackbar from "../../ducks/snackbar"; //->dont do this
import { call, put } from "redux-saga/effects";
export function* handleCheckCoin(action) {
try {
let strSymbol = action.payload;
console.log("Symbol : " + JSON.stringify(strSymbol));
///send out a api request to check Crypto Symbol is valid
yield put(setSnackbar(true, "success", "message"));
} catch (error) {
console.log("error while launching set snack bar action : " + error);
}
}
maybe im missing the point or how sagas work but I'm not sure how to do the following
export default function* (){
yield all([
takeLatest(TOGGLE_MODAL, toggleModal)
]);
}
I have this "initial" function and inside here I call other functions.
one of the functions I call is a generator function and it works correctly
function* myOtherFunction(){
}
say I want to call this function elsewhere in my code, how would I do it?
I want to call it inside an action creator
(it HAS to be a generator as I'm using yield inside it)
You don't call Sagas directly.
You create actions through action creators, which you then dispatch to the store.
You register your sagas in the saga middleware on your store, so they get called each time a specific action is received.
Let's say you have an action CALL_OTHER_FUNCTION and the corresponding action creator callOtherFunction(). you dispatch it somewhere, for example in an component with mapDispatchToProps:
const mapDispatchToProps = dispatch => {
return {
callOtherFn: () => dispatch(callOtherFunction())
};
};
In your saga, you now just have to listen to this action with take(), takeAll(), takeLatest() or another effect creator that suits your needs.
export default function* (){
yield all([
takeLatest(TOGGLE_MODAL, toggleModal),
takeLatest(CALL_OTHER_FUNCTION, myOtherFunction]);
}
after that, your myOtherFunction generator is called on each action you dispatch to the store.
I am new to react and redux xo my questions will sound basic.
What does dispatch means? I am referring to the term dispatching an action.
Why do we need mapDispatchToProps to store actions on redux? We can simply import an action and use it. I have a scenario in which I have to load data when a component is mounted.
#mariazahid mapDispatchToProps will bind the action to your component so that you can pass it down to your presentation components. This is a pattern that is normally used within using Redux with React.
You can import your action and just dispatch the action, but in most scenarios a container -> component pattern is used. A container is where the actions are mapped to and the state and the only goal of this component is to pass this data down to components that are used for presenting that data.
When working in teams, it's a pattern that is easily adoptable. Instead of importing actions from left right and center, you will just have to be aware of the container and how it passes the required actions/data down to the children.
From an implementation perspective, dispatch is just a method that is used to communicate with your reducers
Let say that your action looks something like this
function myAction() {
return { type: 'MY_ACTION' };
}
You're trying to communicate with the reducer that responds to the action type 'MY_ACTION'
In your mapDispatchToProps you'd typically do something like this;
function mapDispatchToProps(dispatch) {
return { actions: bindActionCreators(myActions, dispatch) }
}
Effectively, you're wrapping(binding) your actions to the dispatch method;
function bindActionCreators(actions, dispatch) {
// this is a very trivial implementation of what bindActionCreators does
let wrappedActions = {};
Object.keys(actions).forEach(action =>
// for every action, return a function that calls dispatch on the result of what your action returns
return function(...args) {
// remember here that dispatch is the only way you can communicate with the reducers and you're action's type will determine which reducer responds to return the new state
return dispatch(actions[action](..args));
}
);
}
And so, these "bound" actions are now assigned to a props.actions in your component.
I'm looking through the auth0 sample project for using react, redux and auth0 for a login scenario here. However I'm a bit confused about this particular example where we call this.props.doAuthentication()
// App.js
import { loginUser, fetchQuote, doAuthentication, fetchSecretQuote } from '../actions'
// add a constructor
constructor(props) {
super(props)
this.props.doAuthentication()
}
Here is the action definition
// actions.js
...
const lock = new Auth0Lock('YOUR_CLIENT_ID', 'YOUR_CLIENT_DOMAIN');
export function login() {
// display lock widget
return dispatch => {
lock.show();
}
}
// Listen to authenticated event and get the profile of the user
export function doAuthentication() {
return dispatch => {
lock.on("authenticated", function(authResult) {
lock.getProfile(authResult.idToken, function(error, profile) {
if (error) {
// handle error
return dispatch(lockError(error))
}
localStorage.setItem('profile', JSON.stringify(profile))
localStorage.setItem('id_token', authResult.idToken)
return dispatch(lockSuccess(profile))
});
});
}
}
...
I'm new to redux so maybe this is an obvious answer but
Where is doAuthentication bound to the the props in App.js? Assuming that App.js is the top level root app component.
Doesn't doAuthentication generate a function that expects a dispatch argument? Why don't we do anything in the constructor with the returned function from doAuthentication()? If we don't assign the returned function to anything, does this.props.doAuthentication persist anything or have any effects? Shouldn't it be something like doAuthentication()(someDispatchFunction) Where does this dispatch function come from?
1.Where is doAuthentication bound to the the props in App.js? Assuming that App.js is the top level root app component.
Ans:
The action doAuthentication is bound with the props of App component using the middleware called redux-thunk.
let createStoreWithMiddleware = applyMiddleware(thunkMiddleware, api)(createStore)
let store = createStoreWithMiddleware(quotesApp)
The above two line of code would have done it for your. Read here why redux-thunk is required.
2.Doesn't doAuthentication generate a function that expects a dispatch argument? Why don't we do anything in the constructor with the returned function from doAuthentication()? If we don't assign the returned function to anything, does this.props.doAuthentication persist anything or have any effects? Shouldn't it be something like doAuthentication()(someDispatchFunction) Where does this dispatch function come from?
Ans:
2.1 Yes, the function which is returned by doAuthentication function expects a dispatch method as to be a first parameter.
2.2, 2.3 Here the doAuthentication action creator's job is to create a Redux action which would just listen for the event called authenticated. When we call doAuthentication action creator, it returns a Redux action function which accepts a dispatch method as first parameter and getState method as second. The parameters would be passed by the redux-thunnk middleware.
The redux-thunk middleware would call the redux action which is return from the doAuthentication call since it is connet-ed. Otherwise we have to dispatch the action returned by the doAuthentication as like the below,
this.props.dispatch(doAuthentication())
2.4 We can do as you mention doAuthentication()(someDispatchFunction), but consider this quote
If Redux Thunk middleware is enabled, any time you attempt to
dispatch a function instead of an action object, the middleware will
call that function with dispatch method itself as the first argument.
And, you can find a detailed info about the redux-thunk with this answer