I've got a problem with my reducer. I have created an action creator, reducer, and used 'react-redux' connect to combine both.
When I'm fireing my action, action creator logs, that he just received a new data, but reducer does not log anything (Reducer logs only 3 initial loops). Also, store.getState() which I'm display in console every 5 seconds shows null (which is initial state of my store). Could you help me to deal with the problem?
export const UPDATE_PACKAGE_JSON = 'UPDATE_PACKAGE_JSON';
export function setName(name){
console.log('Action creator just received a name', name);
return {
type: UPDATE_PACKAGE_JSON,
payload: name
}
}
Container
const mapDispatchToProps = (dispatch) =>
bindActionCreators({ setName }, dispatch);
export default connect(null, mapDispatchToProps)(ConfigurationForm) ;
Reducer
import { UPDATE_PACKAGE_JSON } from './../actions/index';
export const packageJson = function (state = null, action){
console.log(UPDATE_PACKAGE_JSON);
switch(action.type){
case UPDATE_PACKAGE_JSON:
return {...state,
name: action.payload};
}
return state;
};
EDIT
Store
import { createStore } from 'redux';
import rootReducer from './../reducers/rootReducer';
const store = createStore(rootReducer);
export default store;
rootReducer
import { combineReducers } from 'redux';
import { packageJson } from './packageJson';
const rootReducer = combineReducers({
packageJson
});
export default rootReducer;
Related
I am trying to use react redux toolkit and pass setter function to set new state on firebase's 'onAuthStateChanged'. The plan was to pass user's state (object or null) to reducer, depending if user is logged in or logged out. This is my first usage of redux, so I can't get why my code doesn't work. There is no errors, but in redux devtools state is always equal to null.
Configure Store:
import { configureStore } from '#reduxjs/toolkit'
import { Provider } from 'react-redux';
import userReducer from './utils/userReducer';
const store = configureStore({
reducer: {
user: userReducer,
}
})
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
My reducer:
import { createSlice } from "#reduxjs/toolkit";
export const userSlice = createSlice({
name: 'user',
initialState: null,
reducers: {
setUser: (state, action) => {
state = action.payload;
}
}
})
export const {setUser} = userSlice.actions;
export default userSlice.reducer;
Where I am dispatching it:
import { setUser } from '../utils/userReducer'
import { useDispatch } from 'react-redux'
const dispatch = useDispatch()
const handleLogin = async (e) => {
e.preventDefault()
const { user } = await logInWithEmail(email, password)
await setCurrentUser(() => dispatch(setUser))
}
Firebase function, where I am trying to use reducer:
export const setCurrentUser = async (setUser) => {
await onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser)
})
}
I understand, that with useContext it would be much easier, but I am trying to learn redux by implying it.
Try like that:
import { setUser } from '../utils/userReducer'
import { useDispatch } from 'react-redux'
const dispatch = useDispatch()
const handleLogin = async (e) => {
e.preventDefault()
const { user } = await logInWithEmail(email, password)
// This line updated
await setCurrentUser((currentUser) => dispatch(setUser(currentUser)))
}
The reason:
your setCurrentUser function prop setUser is just function () => dispatch(setUser), but this function does not receive any prop, and dispatch(setUser) does not do anything. you need to pass value (payload) to reducer function.
Additionally, try passing dispatch itself as prop and dispatch inside of onAuthStateChanged.
export const setCurrentUser = async (dispatch) => {
await onAuthStateChanged(auth, (currentUser) => {
dispatch(setUser(currentUser))
})
}
import setUser reducer function if handleLogin and setCurrentUser function is in different files separately.
I'd managed to get some of my earlier functions state in devtools as below:
Reducers function in DevTools
But when I tried to query some of the events in my interactions, the functions state werent able to display it. Below are my codes and settings, basically the flow is interactions > actions > reducers
interaction code:
export const loadAllOrders = async (exchange, dispatch) => {
// Fetch cancelled orders with the "Cancel" event stream
const fromBlock = 0;
const toBlock = "latest";
const cancelFilter = exchange.filters.CancelOrder();
const cancelStream = await exchange.queryFilter(cancelFilter, fromBlock, toBlock);
console.log(cancelStream)
// Format cancelled orders
const cancelledOrders = cancelStream.map((event) => event.args);
// Add cancelled orders to the redux store
dispatch(cancelledOrdersLoaded(cancelledOrders));
}
from my actions:
export const cancelledOrdersLoaded = (cancelledOrders) => {
return {
type: 'CANCELLED_ORDERS_LOADED',
payload:cancelledOrders
}
}
from my reducers:
export const exchange = (state = initialState, action) => {
switch (action.type) {
case 'EXCHANGE_LOADED':
return { ...state, loaded:true, contract: action.payload }
case 'CANCELLED_ORDERS_LOADED':
return { ...state, cancelledOrders: action.payload }
default:
return state
}
my configureStore
// For redux dev tools
const devTools = window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
const store = createStore(
rootReducer,
compose(applyMiddleware(thunk),devTools)
)
Thanks in advance
I haven't worked with redux for quite some time now, but from a quick look at some of my older repos, it seems like you didn't set up your store correctly.
This is what I have there,
import { applyMiddleware, createStore, compose, combineReducers } from "redux"
import thunk from "redux-thunk"
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const rootReducer = combineReducers({
reducers...
})
export const store = createStore(rootReducer, composeEnhancers(applyMiddleware(thunk)))
I am working on the application which is purely redux-saga, but as the application is growing, the number of files is also growing. To solve this issue I am trying to setup redux-starter-kit to my current application.
Here is my store configuration file index.js
import { configureStore, getDefaultMiddleware } from 'redux-starter-kit'
import rootReducer from '../reducers'
export const store = configureStore({
reducer: rootReducer,
middleware: [...getDefaultMiddleware()]
})
old set up for just redux-saga without redux-starter-kit
// import createSagaMiddleware from 'redux-saga'
// import { initSagas } from '../initSagas'
// import rootReducer from '../reducers'
// import { loadState, saveState } from './browserStorage'
// function configureStore () {
// const sagaMiddleware = createSagaMiddleware()
// const persistedState = loadState()
// const createdStore = createStore(
// rootReducer,
// persistedState,
// applyMiddleware(sagaMiddleware)
// )
// initSagas(sagaMiddleware)
// return createdStore
// }
// export const store = configureStore()
// store.subscribe(() => {
// saveState(store.getState())
// })
the problem:
when I set up the redux-starter-kit the old sagas are not working.
Long story short:
How can I set up my existing redux-saga application with redux-starter-kit, without disturbing the current saga files?
Thank you in advance.
redux-starter-kit does not include sagaMiddleware by default [1]. You'll need to add it to the middleware list and initialize the sagas yourself.
In your case I believe this should work:
import createSagaMiddleware from 'redux-saga'
import { configureStore, getDefaultMiddleware } from 'redux-starter-kit'
import rootReducer from '../reducers'
import { initSagas } from '../initSagas'
const sagaMiddleware = createSagaMiddleware();
export const store = configureStore({
reducer: rootReducer,
middleware: [...getDefaultMiddleware(), sagaMiddleware]
})
initSagas(sagaMiddleware);
[1] https://redux-starter-kit.js.org/api/getdefaultmiddleware
I'm using a Net Core, React-Redux boiler-plate, and when I run the fetch api action, the reducer state does not change at all.
Here is my action
import axios from "axios";
import config from '../config';
const ROOT_URL = config[process.env.NODE_ENV].api;
export const FETCH_EVENTS = "FETCH_EVENTS";
export function fetchEvents() {
const url = ROOT_URL +"/Event/GetAllEvents";
const request = axios.get(url);
return {
type: FETCH_EVENTS,
payload: request
};
}
my index reducer:
import { combineReducers} from 'redux';
import { routerReducer } from 'react-router-redux';
import dataReducer from './dataReducer'
const reducers = {
events: dataReducer
};
const rootReducer = combineReducers({
...reducers,
routing: routerReducer
});
export default rootReducer;
and my reducer:
import { FETCH_EVENTS } from "../actions/ExtractActions";
export default function (state = [], action) {
switch (action.type) {
case FETCH_EVENTS:
console.log("inside reducer")
return [action.payload, ...state];
}
return state;
}
So I add this code in the Home component:
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchEvents }, dispatch);
}
function mapStateToProps(state) {
return {
events: state.events
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Home);
but when I try to run the action and try to see if the reducer state has changed, I get on console log an empty array for "this.props.events". Even though if I am trying to store api data to the state, I even tried modifying the reducer method and simply returning a string, but this.props.events returns an empty array [] again. I am guessing my redux is not working but I don't know why. I've been debugging all night long
componentWillMount() {
this.props.fetchEvents()
console.log(this.props.events)
}
I found the error. For some reason I had to call this.props.events in the render() method and not componentwillmount.
axios.get() is an async function. That's why you couldn't see the updated state when you logged it right after fetching the events. I would recommend you to use the redux-devtools-extension for debugging. Hope this helps. Cheers!
I have created a database in firebase the schema is below:
Now All I have been trying to do is just have it show up when I do a console log but nothing shows up.
Below is the code for my JobsActions.js
import firebase from 'firebase';
import {
JOBS_FETCH_SUCCESS
} from './types';
export const jobsFetch = () => {
return (dispatch) => {
firebase.database().ref('/jobs')
.on('value', snapshot => {
dispatch({ type: JOBS_FETCH_SUCCESS, payload: snapshot.val() });
});
};
};
This is my reducer:
import {
JOBS_FETCH_SUCCESS
} from '../actions/types';
const INITIAL_STATE = {
// jobs: 'RCCA'
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case JOBS_FETCH_SUCCESS:
console.log(action);
return state;
//return action.payload;
default:
return state;
}
};
This is the JobsList
import _ from 'lodash';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { View, Text } from 'react-native';
import { jobsFetch } from '../actions';
class JobsList extends Component {
componentWillMount() {
this.props.jobsFetch();
}
render() {
return (
<View style={{ paddingTop: 20 }}>
<Text>Hello</Text>
</View>
);
}
}
export default connect(null, { jobsFetch })(JobsList);
I have authentication using firebase and its not a connection to firebase thats an issue, From what I see, it seems like maybe the ref path is wrong in the Actions file?
You main problem here is not with Firebase actually, since I believe everything else is allright, but with React-Redux.
When you are connecting a component to the store, the connect function recieves two functions. The first one (usually called mapStateToProps) recieves the state and returns an object that will be added to the props. In this case, you are not using it, so passing null is a valid decision.
The second one (usually called mapDispatchToProps) receives the dispatch as a parameter and should return an object with the functions that will be inserted to the props that can be used to dispatch new actions. In this case, you are just passing an object as the second parameter of the connect { jobsFetch }.
When you do this.props.jobsFetch(); you are actually returning the function that receives the dispatch, so nothing is actually executed.
Your mapDispatchToProps should be something similar to this
const mapDispatchToProps = dispatch => {
return {
jobsFetch : () => dispatch(jobsFetch())
}
}
export default connect(
null,
mapDispatchToProps
)(JobsList)
Here, I'm assuming that you are in fact using Redux thunk since you are returning a function that receives the dispatch as a parameter in your actions.
As you may see, we first call the jobsFetch() in order to get the function that receives the reducer, and then we dispatch it.
Let me know if this does not work! There may be something else that is not correct, but this is something that should be addressed. Hope it helps!