Just discovered that I can use the getState() to pass state values to action creators. However I am noticing that getState() is returning all the combined states rather than the one specified in the argument. What am I doing wrong, as I don't suppose this is the correct behavior?
Reducer:
import { combineReducers } from "redux";
import { reducer as reduxForm } from "redux-form";
import authReducer from "./authReducer";
export default combineReducers({
auth: authReducer,
form: reduxForm
});
Action creator snippet:
export const handleProviderToken = token => async (dispatch, getState) => {
let testState = getState("auth");
console.log(testState);
const res = await axios.get(`${API_URL}/api/testEndpoint`);
dispatch({ type: FETCH_USER, payload: res.data });
};
The console.log(testState) is showing me the entire state tree object (auth and form, rather than just auth).
Quoting redux-thunk documentation
The inner function receives the store methods dispatch and getState as
parameters.
and quoting from redux's documentation
getState() Returns the current state tree of your application. It is
equal to the last value returned by the store's reducer.
So the getState you pass thanks to redux-thunk, is actually redux's getState() function itself and thus it is the default behavior.
To get a specific value from your state tree, you can either use one of the following
const { auth } = getState()
// OR
const testState = getState()
const auth = testState.auth
It is the correct behavior. From docs:
Returns the current state tree of your application. It is equal to the
last value returned by the store's reducer.
It is correct behavior. You will need to pick the reducer key from the complete state.
export const handleProviderToken = token => async (dispatch, getState) => {
let testState = getState();
let authReducer = testState.auth;
const res = await axios.get(`${API_URL}/api/testEndpoint`);
dispatch({ type: FETCH_USER, payload: res.data });
};
What works in similar case for me is
const lastFetchedPage =getState().images.lastFetchedPage;
I do not know how it goes with guidelines, however.
Related
So what I'm trying to do is basically call an async function than ask mapStateIntoProps to pass it into props into the actual component. When I do I get a console.log() that shows pending my data is in there tho.
here is my first file that has the async func
export const getIdMovie = async (state,movieId)=>{
let data= await axios
.get(
`https://api.themoviedb.org/3/movie/${movieId}?
api_key=${APIKEY}&language=en-US`
)
let results=data.data
return results
}
this is where i try to call it on the second file
injectDataReducer(store, { key: "movie", reducer: MovieReducer });
const mapStateToProps = (state, ownProps) => ({
movie: getIdMovie(state,ownProps.movieId)
});
If getIdMovie is an action creator, you will have to use redux-thunk.Reducer updates the store asynchronously when you dispatch and action to avoid changing same data by multiple dispatch actions.
````Also, you will have to first set the state i.e. movies into reducer and then update the data from there into your component.```
I am developing a react-native app and new to redux. I've 3 screens and almost all state of all screens dependent on each other.
e.g First screen scans the product, second screen takes customer details and third screen displays the summary from of products and customer.
I am hitting the wall since 2 days to create the state structure and I end up with combineReducers. But in combine reducers, each reducer maintains its own slice of state and doesn't let me access or update the state of another reducer.
So,
Q1. Should I continue with combieReducers or should maintain single reducer only?
Q2. If combineReducers is OK, how should access or update the same state along all reducers?
for u r first question yes u have to combine because combineReducers will give all reducers data in single object
example:
const rootReducer = combineReducers({
posts: PostsReducer,
form: formReducer
});
inside component
function mapStateToProps(state) {
return { posts: state.posts };
}
export default connect(mapStateToProps, { createPost })(PostsIndex);
in the above code through Redux connect you can access state which is produced by combine reducera like this.props.posts inside your component
To update the you need to triger an action which go through all reducers and based on type you can update the state
example:
export function createPost(values, callback) {
const request = axios
.post(`${ROOT_URL}/posts${API_KEY}`, values)
.then(() => callback());
return {
type: CREATE_POST,
payload: request
};
}
using middleware you can achieve the funtionality
export default ({ dispatch, getState }) => next => action => {
next(action);
const newAction = { ...action, payload: "",state:getState () };
dispatch(newAction);
};
I'm a little new to using thunk getState I have been even trying to console.log the method and get nothing. In state I see that loginReducer has they key property which I need to make API calls. status(pin): true
key(pin): "Ls1d0QUIM-r6q1Nb1UsYvSzRoaOrABDdWojgZnDaQyM"
Here I have a service:
import axios from 'axios'
import {thunk, getState} from 'redux-thunk'
import MapConfig from '../components/map/map-config'
const origin = 'https://us.k.com/'
class KService {
getNorthAmericaTimes() {
return (dispatch, getState) => {
const key = getState().key
console.log('This is time key,', key)
if (key) {
dispatch(axios.get(`${origin}k51/api/datasets/k51_northamerica?key=${key}`))
}
}
// const url = `${origin}k51/api/datasets/k51_northamerica?key=${urlKey}`
// return axios.get(url)
}
}
export default new K51Service()
However in my corresponding action I get that Uncaught TypeError: _kService2.default.getNorthAmericaTimes(...).then is not a function
This is what the action function looks like :
export function getKNorthAmericaTime(dispatch) {
KService.getNorthAmericaTimes().then((response) => {
const northAmericaTimes = response.data[0]
dispatch({
type: ActionTypes.SET_NORTH_AMERICA_TIMES,
northAmericaTimes
})
})
}
I'm assuming it probably has to do with the if block not getting executed.
You should move your axios.get() method to your action creator and pass the promise to redux thunk, then when the promise is resolved dispatch the action with the response data so it can be processed by the reducer into the app's state.
actions
import axios from "axios";
export function fetchData() {
return (dispatch, getState) => {
const key = getState().key;
const request = axios.get();// use your request code here
request.then(({ response}) => {
const northAmericaTimes = response.data[0]
dispatch({ type: ActionTypes.SET_NORTH_AMERICA_TIMES, payload: northAmericaTimes});
});
};
}
Here's a very simple example of using axios with redux-thunk:
https://codesandbox.io/s/z9P0mwny
EDIT
Sorry, I totally forgot that you need to go to the state before making the request.
As you can see go to the state in your function, get the key from it, make the request and when the promise is resolved, dispatch the action with the response data. I've updated the live sample so you can see it working.
Again sorry...
I have a chat-app that uses React, Redux and Firebase. I'm also using thunkmiddleware to do the async updates of the state with Firebase.
I successfully get everything I need, except that everything depends of a previously hard-coded variable.
The question is, how can I call inside my ActionCreators the getState() method in order to retrieve a piece of state value that I need in order to fill the rest of my states?
I currently have my auth: { uid = 'XXXZZZYYYY' }... I just need to call that like
getState().auth.uid
however that doesn't work at all.
I tried a lot of different questions, using mapDispatchToProps, etc. I can show my repo if needed.
Worth to mention that I tried following this other question without success.
Accessing Redux state in an action creator?
This is my relevant current code:
const store = createStore(
rootReducer,
defaultState,
applyMiddleware(thunkMiddleware));
And
function mapDispatchToProps(dispatch) {
watchFirebase(dispatch); // to dispatch async Firebase calls
return bindActionCreators(actionCreator, dispatch);
}
const App = connect(mapStateToProps, mapDispatchToProps)(AppWrapper);
Which I am exporting correctly as many other not pure functions work correctly.
For instance, this works correctly:
export function fillLoggedUser() {
return (dispatch, getState) => {
dispatch({
type: C.LOGGED_IN,
});
}
}
However as suggested below, this doesn't do a thing:
const logState = () => ( dispatch, getState ) => {
console.log(getState());
};
In general your thunked action creator should look something like the below (I have used a post id as an example parameter):
const getPost = ( postId ) => ( dispatch, getState ) => {
const state = getState();
const authToken = state.reducerName.authToken;
Api.getPost(postId, authToken)
.then(result => {
// where postRetrieved returns an action
dispatch(postRetrieved(result));
});
};
If this is similar to what you have then I would log your state out and see what is going on with a simple thunk.
const logState = () => ( dispatch, getState ) => {
console.log(getState());
};
I use redux's combineReducers() helper function to combine two reducers like so:
const rootReducer = combineReducers({
user: userReducer,
accounts: accountsReducer
})
I know each reducer can only modify a slice of the store it's assigned to, "user" and "accounts" in this case.
How can i modify the "user" part of my store from my accounts reducer?
You can't.
You can either listen to the same action in both reducers, or if you need to update the user state based on the update to the accounts' state, then you can use Redux thunks - https://github.com/gaearon/redux-thunk
const action = () => (dispatch, getState) => {
// dispatch action that accounts reducer listens to
dispatch({
type: 'SOME_ACTION'
})
// get the new accounts state
let { accounts } = getState()
// dispatch action that user reducer listens to, passing the new accounts state
dispatch({
type: 'ANOTHER_ACTION',
payload: {
accounts
}
})
}
// call with
dispatch(action())