I am trying to translate the following from ES2015 to vanilla javascript:
fileA.js
export const checkout = ({ dispatch }) => {
dispatch(types.CHECKOUT_REQUEST)
}
fileB.js
import checkout;
checkout();
So far (using https://babeljs.io/repl/) I have:
fileA2015.js:
module.exports = {
checkout: function (_ref) {
dispatch = _ref.dispatch;
dispatch(types.CHECKOUT_REQUEST)
}
};
But I cannot figure out what to pass to checkout in fileB to have access to the correct _ref. What is this and where does it come from?
export const checkout = ({ dispatch }) => {
dispatch(types.CHECKOUT_REQUEST)
}
In the above function you are destructuring an object, which is expected to have a dispatch property. Where in dispatch is a callback function.
when you pass in the data object as a parameter, because of { dispatch }, which destructures the object that is passed in, it is expected to have dispatch property.
var data = {
dispatch: (type) => {
.......
}
};
So when checkout method is referenced and invoked in fileB.js, then you will have to pass in the data object at this point.
fileB.js
var data = {
dispatch: (type) => {
.......
}
};
import checkout;
checkout(data);
Let's note a few things here:
export const checkout = ({ dispatch }) => {
dispatch(types.CHECKOUT_REQUEST)
}
In the code above, checkout() is a function that expects a single parameter -- specifically an object with the property dispatch. dispatch is also expected to be a function.
If you don't pass any parameters to checkout() (or an object that doesn't have a dispatch property), dispatch will be undefined.
Therefore you need to pass something like:
checkout({ dispatch: function(){} })
Related
export default function applyMiddleware(...middlewares) {
return (createStore) => (...args) => {
const store = createStore(...args)
let dispatch = () => {
throw new Error(
'Dispatching while constructing your middleware is not allowed. ' +
'Other middleware would not be applied to this dispatch.'
)
}
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args),
}
const chain = middlewares.map((middleware) => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch,
}
}
}
This code is the actual implementation of applymiddleware form https://github.com/reduxjs/redux/blob/4.x/src/applyMiddleware.js . In this code mapping a middlewares passing middlewareAPI as argument to each middelware
let's take example thunk function
In that thunk function I am getting a dispatch and getState as arguments to handle async actions
please observe my question i am try to understand my doubt clearly
In that applyMiddleware function each middleware is passing a middlewareAPI as argument but inside middlewareAPI object dispatch is a some anonymous function returning a other function named as disptach. In the place of store we are passing a middlewareAPI object But how thunk function is getting a composed disptach as argument
My Doubts:
1.dispatch: (...args) => dispatch(...args) what is the meaning to this line and how it's going help in that code
2.we are passing middlewareAPI in the place of store object before store.dispatch function is updating and my thunk function is getting arguments as diapatch and getState. From redux-thunk my thunk function will be calling with diapatch and getState arguments. How dispatch function is getting updated dispatch function as argument to my thunk function
I'm new to react, redux and tyring to understand the redux-toolkit tutorial i follow. I have the slice as follows.
const initialState = {
count: 0,
};
export const counterSlice = createSlice({
name: "counter",
initialState,
reducers: {
increment: (state) => {
state.count += 1;
},
},
});
export const { increment } = counterSlice.actions;
export default counterSlice.reducer;
export const incrementTest = () => (dispatch) => {
dispatch(increment());
};
Then I use that incrementTest action as follows
<button onClick={() => dispatch(incrementTest())}> + </button>
I want to understand following.
In following fuction
export const incrementTest = () => (dispatch) => {
dispatch(increment());
};
we return a function which takes argument as dispatch then call that provided dispatch function with argement of another function increment which is defined above and exported.
However when we call this function we use dispatch(incrementTest()) providing incrementTest as a param to dispatch. I don't understand this concept . Which concept in javascript should i further study to learn this ?
Also increment reducer take state as parameter ( and action also in some cases ). Who provide this (state,action) to this function as we call it as dispatch(incrementTest())
So this:
export const incrementTest = () => (dispatch) => {
dispatch(increment());
};
is an example for a thunk, a function that gets called (by a redux middleware) with two arguments, dispatch and getState. It is typically used to coordinate async work since you can await stuff inside the function or deal with promises. Look up the thunk middleware if you want to know more. I'm not sure why they made this action a thunk, there's no need for it, maybe testing.
To your second question, the library does. All you do is call dispatch() with an action, the library calls the reducer function with the current state and your action. Think of it as emitting an event. Your job is to create the event, the library takes care of updating the global state accordingly. The reducer is written declaratively, sort of. As in "how would the global state need to change if that specific event happened?".
example store
getters: {
setName: (state) => (string: string) => {
state.user.username = string;
},
setUser: (state) => {
setName('Tom'); // setName is undefined.
}
}
Is there any way to access the setName inside an arrow function?
Example only show you can get this inside normal functions
https://pinia.vuejs.org/core-concepts/getters.html#accessing-other-getters
First of all, as Phil pointed out, getters feature should not mutate the state. As mutations are not included in Pinia, actions is the way to go.
Also, Arrow functions are meant to not have a this object reference. So, If you want to access any of the other store methods or variables in the state you should create an action with a regular javascript function syntax, like
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: (): myState => ({
user: {name: 'myname'},
}),
getters: {
getName: (state: myState) => state.user.name,
},
actions: {
setName(newName: string) {
this.user.name = newName
},
},
})
Then in any external file where you already imported the defined store, call the action just like this
import { useUserStore} from '~/stores/user'
const store = useUserStore()
store.setName('Tom')
Note: In Pinia actions you may want to always use regular javascript function syntax as those are in charge of changing data in your state.
I'm trying to pass in a variable into an axios request in my action:
export function searchRequest(search){
return(dispatch)=>{
console.log('in search', search)
return axios.get(`http://localhost:4000/reports/${search}`)
.then(response => {
dispatch(searchInfo(response.data))
})
}
}
When I console log search, it does not register.
However, when I remove the return dispatch and console log response.data in the .then, I get the desired data, but I'm not able to use dispatch.
The question is, why am I not able to pass in search in this way?
Edit: this is in react native
I'm not sure how you connect this function to Redux in React-native but I think it works like you're doing it with regular React.
The searchRequest function return a new function with one variable dispatch. search will be "static" with the value you've passed in when calling searchRequest, so probably null or undefined or some hardcoded value.
You should to this the other way around:
import {connect} from 'react-redux'
const searchRequest = (dispatch) => {
return async (search) => {
const response = await axios.get(`http://localhost:4000/reports/${search}`)
dispatch(searchInfo(response.data))
}
}
class YourComponent extends Component {
....
onSearch = (search) => {
this.props.doSearch(search)
}
....
}
const mapDispatch = (dispatch) => ({
doSearch: searchRequest(dispatch)
})
export connect(null, mapDispatch)(YourComponent)
This is how it looks with "normal web"-React. Maybe in native it looks different. Notice that dispatch is provided as parameter once. Afterwards when calling doSearch the same instance of dispatch is used inside the function.
This might be a question of best practices but I'd appreciate an explanation on why this doesn't work. I'm using Typescript + Redux + Thunk and trying to call actions like this:
export const requestUserDashboards = createAction<DashboardModel>(Type.REQUEST_USER_DASHBOARDS);
Dispatch in the fetch:
export const fetchDashboards = () => {
return async (dispatch: Dispatch, getState: any) => {
try {
dispatch(requestUserDashboards({
currentDashboard: getState.currentDashboard,
dashboards: getState.dashboards,
hasDashboards: false,
error: getState.error
}))
...
}
})
}
Here's the corresponding reducer:
export const dashboardReducer = handleActions<RootState.DashboardState, DashboardModel>(
{
[DashboardActions.Type.REQUEST_USER_DASHBOARDS]: (state = initialState, action): RootState.DashboardState => ({
currentDashboard: action.payload!.currentDashboard,
dashboards: action.payload!.dashboards,
hasDashboards: action.payload!.hasDashboards,
error: action.payload!.error
})
},
initialState
);
dispatch is working, however, getState doesn't correctly collect the current store state. I'm testing this by doing the following in the component receiving the updated store:
componentWillReceiveProps(nextProps: Login.Props) {
console.log(nextProps.defaultAccounts.defaultAccount);
}
Calling this in the component using:
this.props.defaultAccountActions.fetchUserDefaultAccount();
The action is working as the values from the fetch are being captured.
However, where I am using the getState.xxxx, these values are returning as undefined:
index.tsx:84 Uncaught TypeError: Cannot read property 'defaultAccount' of undefined
The initialState from my reducer is working. I can see this from doing the console.log(this.props.defaultAccounts.defaultAccount) from the componentWillMount() function.
I'm not sure what else I can provide. I think I'm actually just fundamentally misunderstanding how actions/reducers manage the store.
Questions
I am trying to get the current store values by using the getState.xxxx in the dispatch. Is this the correct way to do this?
isn't getState a function in that place? So you would need to do something
const state = getState();
and then use state inside dispatch
found in documentation, yeah it is a function at that place so you should firstly invoke a function to get state and then use it (e.g. from documentation below)
function incrementIfOdd() {
return (dispatch, getState) => {
const { counter } = getState();
if (counter % 2 === 0) {
return;
}
dispatch(increment());
};
}
If you are using mapstatetoprops in your component you can use that to get the values from store. mapStateToProps first argument is actually the Redux state. It is practically an abstracted getState().
const mapStateToProps = function(state, ownProps) {
// state is equivalent to store.getState()
// you then get the slice of data you need from the redux store
// and pass it as props to your component
return {
someData: state.someData
}
}