I am currently working with the redux toolkit I am facing an issue for the last 2 days.
The problem is when I am trying to select a state using the useSelector undefined is returned.
The code is given below:
reducer
import { createSlice } from "#reduxjs/toolkit";
import axios from "axios";
const SchoolDataReducer = createSlice({
name: "datasets",
initialState: [],
reducers: {
getSchoolRecords(state, action) {
return action.payload
}
}
})
export const { getSchoolRecords } = SchoolDataReducer.actions;
export default SchoolDataReducer.reducer;
export function getDataTriger() {
return async function getSchoolDataThunk(dispatch, getstate) {
try {
const res = await axios.get("/getschool")
dispatch(getSchoolRecords(res.data))
} catch (error) {
console.log(error);
}
}
}
store
import { configureStore } from "#reduxjs/toolkit";
import SchoolDataReducer from "./SchoolData"
const store = configureStore({
reducer: {
School: SchoolDataReducer
}
});
export default store;
result
const maindATA = useSelector(State => State.datasets)
console.log(maindATA); // undefined
Your whole state data structure is { School: [] }, you can get the state slice using useSelector(state => state.School).
Please see https://redux-toolkit.js.org/api/configureStore#reducer about the data structure of the redux state. So you can change the reducer option of configureStore like below:
const store = configureStore({
reducer: {
datasets: SchoolDataReducer
}
});
// In component:
const maindATA = useSelector(state => state.datasets)
Related
I'm trying to convert an existing project to configureStore from createStore.
store.js :
export default configureStore({
reducer: {
articlesList: loadArticlesReducer
}
});
home.js :
const articlesList = useSelector((state) => state.articlesList);
const dispatch = useDispatch()
useEffect(() => {
dispatch(getArticles());
})
articleSlice.js :
const articleSlice = createSlice({
name: 'articles',
initialState : [],
reducers : {
loadArticlesReducer: (state, action) => {
console.log("WE NEVER REACH THIS CODE") <=== the problem is here
state = action.payload;
}
}
});
export const { loadArticlesReducer } = articleSlice.actions;
export const getArticles = () => dispatch => {
fetch("https://....")
.then(response => response.json())
.then(data => {
dispatch(loadArticlesReducer(data))
})
};
The problem, as stated in the comment, is that getArticles action never dispatches the data to loadArticlesReducer.
What am I missing here?
loadArticlesReducer is an action creator, not a reducer function. I suggest renaming the action creator so its purpose isn't confusing to future readers (including yourself) and actually exporting the reducer function.
Example:
const articleSlice = createSlice({
name: 'articles',
initialState : [],
reducers : {
loadArticlesSuccess: (state, action) => {
state = action.payload;
}
}
});
export const { loadArticlesSuccess } = articleSlice.actions;
export const getArticles = () => dispatch => {
fetch("https://....")
.then(response => response.json())
.then(data => {
dispatch(loadArticlesSuccess(data));
});
};
export default articleSlice.reducer; // <-- export reducer function
import articlesReducer from '../path/to/articles.slice';
export default configureStore({
reducer: {
articlesList: articlesReducer
}
});
You may also want to consider converting getArticles to a more idiomatic RTK thunk function using createAsyncThunk. You'd use the slice's extraReducers to handle the fulfilled Promise returned from the Thunk. Example:
import { createAsyncThunk, createSlice } from '#reduxjs/toolkit';
export const getArticles = createAsyncThunk(
"articles/getArticles",
() => {
return fetch("https://....")
.then(response => response.json());
}
);
const articleSlice = createSlice({
name: 'articles',
initialState : [],
extraReducers: builder => {
builder.addCase(getArticles.fulfilled, (state, action) => {
state = action.payload;
});
},
});
export default articleSlice.reducer;
As per the documentation, you'll need to replace the following line:
export default configureStore({
reducer: {
articlesList: loadArticlesReducer // <= This currently points to the exported actions and not the reducer
}
});
With this one:
import articleReducer from './articleSlice.js'
export default configureStore({
reducer: {
articlesList: articleReducer
}
});
You'll need to export the reducer from the articleSlice.js of course:
export default articleSlice.reducer;
As a general tip, always reproduce the examples from the documentation using exactly the same setup and naming, and once it works, customize the code accordingly in a slow step by step manner. It's easy to miss something while replicating such complicated setups if there's no 1-to-1 correspendence with the original code.
I am Creating a React-app and using Reduxjs Toolkit for state management. I am not able to understand why ChannelID and Channelname are undefined here.
Here is the App.js
import { useSelector } from 'react-redux'
import { selectChannelId, selectChannelname } from '../../reduxjs toolkit/appSlice'
const Chats = () => {
const user = JSON.parse(localStorage.getItem("user"))
const data = localStorage.getItem("userData");
const [userData, setUserData] = useState(JSON.parse(localStorage.getItem("userData")))
const ChannelId = useSelector(selectChannelId) // Giving Error Here
const channelName = useSelector(selectChannelname) // Giving Error Here
Here is the appSlice
import { createSlice } from "#reduxjs/toolkit";
export const appSlice = createSlice({
"name":'app',
initialState:{
channelId:null,
channelName:null,
},
reducers:{
setChannelInfo: (state,action)=>{
state.channelId = action.payload.channelId
state.channelName = action.payload.channelName
},
}
})
export const {setChannelInfo}= appSlice.actions
export const selectChannelId = (state) => state.app.channelId
export const selectChannelname = (state) => state.app.channelName
export default appSlice.reducer;
Error Message
Code for Store
import { createStore } from "redux";
import reducers from "./reducers"
const store = createStore(reducers, {}, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())
export default store;
Use configureStore to create your store, this is "a friendly abstraction over the standard Redux createStore function that adds good defaults to the store setup for a better development experience." quoted from the rtk doc.
For your case it will be as such
import appReducer from './%%WhereYourSliceResides
import { configureStore } from '#reduxjs/toolkit'
export const store = configureStore({
reducer: {
app: appReducer,
},
})
Then the selector will pick up state.app from your store.
I am trying to store data in my redux store using a reducer when we get data from B/E API and trying to store data in the reducer(store). But not working. My code is correct to me. But somehow it's not working.
My Store:-
import createSagaMiddleware from 'redux-saga';
import { configureStore } from '#reduxjs/toolkit';
import rootReducer from './rootReducer';
import rootSaga from './rootsaga';
// saga middleware
const sagaMiddleware = createSagaMiddleware();
// redux store
const store = configureStore({
reducer: rootReducer,
middleware: [sagaMiddleware],
});
// run saga middleware
sagaMiddleware.run(rootSaga);
export default store;
My root saga:-
import { all, takeEvery } from '#redux-saga/core/effects';
import * as categoryActionTypes from '../redux/types/categoryActionTypes';
import * as productActionTypes from '../redux/types/productActionTypes';
import { getAllStudents } from './sagas/categorySaga';
import { getAllProductWatcher } from './sagas/productSaga';
export default function* root() {
yield all([
takeEvery(categoryActionTypes.GET_ALL_CATEGORY, getAllStudents),
takeEvery(productActionTypes.GET_ALL_PRODUCT_ACTION, getAllProductWatcher),
]);
}
My Reducer:- (console.log() not working) That's means not store data into reducer
import * as actionTypes from '../types/productActionTypes';
const initialState = {
product: [],
isLoading: true,
error: true,
};
// reducer
export default function productReducer(state = initialState, action) {
switch (action.types) {
case actionTypes.GET_ALL_PRODUCT_SUCCESS:
console.log(action.data);
return {
...state,
product: action.data,
isLoading: false,
error: false,
};
default:
return state;
}
}
This is my saga method and this is how I store data into my reducer:-
import { put } from '#redux-saga/core/effects';
import { GET_ALL_PRODUCT_SUCCESS } from '../types/productActionTypes';
import { createRequest } from '#utils/create-request';
export function* getAllProductWatcher(upload) {
try {
const Axios = yield createRequest(upload);
const res = yield Axios.get('http://localhost:8080/product');
if (res) {
**//Tying to store API data to my reducer**
yield put({
type: GET_ALL_PRODUCT_SUCCESS,
data: res.data,
});
}
} catch (e) {
console.log(e);
}
}
I really need your help... Thanks.
I am trying to store users fetched by random users api and trying to dispatch it to my store i have store users with an empty array, when i am trying to get users using useSelector i am getting an undefined object.
Here is my store.js:
import { configureStore } from "#reduxjs/toolkit";
import counterReducer from "../features/counter/counterSlice";
import userReducer from "../features/users/userSlice";
export const store = configureStore({
reducer: {
counter: counterReducer,
user: userReducer,
},
});
Here is userSlice.js
import { createSlice } from "#reduxjs/toolkit";
export const userSlice = createSlice({
name: "users",
initialState: {
userArray: [],
},
reducers: {
getUsers: (state, action) => {
state.userArray = action.payload;
}
}
})
export const { getUsers } = userSlice.actions;
export const selectUsers = (state) => state.users.userArray;
export default userSlice.reducer;
Here is App.js
import logo from './logo.svg';
import './App.css';
import {useSelector, useDispatch } from 'react-redux';
import { getUsers, selectUsers } from './features/users/userSlice';
function App() {
const dispatch = useDispatch();
const users = useSelector(selectUsers);
const fetchUsers = async () => {
fetch("https://gorest.co.in/public/v2/users")
.then((response) => response.json())
.then((data) => {
console.log("data=====", data);
dispatch(getUsers(data));
});
};
return (
<div className="App">
<header className="App-header">
<button onClick={fetchUsers}>Get Users</button>
{users.length > 0 &&
users.map((user) => {
<li>user.name</li>;
})}
</header>
</div>
);
}
export default App;
you are mixing up state.user and state.users
either rename user in configureStore to users or use state.user.userArray
I'm just starting with React and Redux and stumbled upon something I can't figure out by myself - I think that Redux state is not changing and it's causing (some of) errors. I'm checking state with use of remote-redux-devtools#0.5.0.
My code:
Categories.js:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { getCategories } from '../../actions/categories';
export class Categories extends Component {
static propTypes = {
categories: PropTypes.array.isRequired
};
componentDidMount() {
this.props.getCategories();
}
render() {
return (
<div>
Placeholder for categories.
</div>
)
}
}
const mapStateToProps = state => ({
categories: state.categories.categories
});
export default connect(mapStateToProps, { getCategories })(Categories);
../../actions/categories.js:
import axios from "axios";
import { CATEGORIES_GET } from "./types";
export const getCategories = () => dispatch => {
return axios
.get("/api/notes/categories/")
.then(res => {
dispatch({
type: CATEGORIES_GET,
payload: res.data
});
})
.catch(err => console.log(err));
};
reducers/categories.js:
import { CATEGORIES_GET } from '../actions/types.js';
const initialState = {
categories: []
};
export default function (state = initialState, action) {
switch (action.type) {
case CATEGORIES_GET:
return {
...state,
categories: action.payload
};
default:
return state;
}
}
store.js:
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'remote-redux-devtools';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const initialState = {};
const middleware = [thunk];
const store = createStore(
rootReducer,
initialState,
composeWithDevTools(applyMiddleware(...middleware)));
export default store;
reducers/index.js
import { combineReducers } from "redux";
import categories from './categories';
export default combineReducers({
categories,
});
Using remote-redux-devtools, I've never seen anything in my state. Currently this code above gives me 3 errors, two of them being
this.props.getCategories is not a function
My guess is that because there is some issue with Categories class, it's not passing anything to state and it could be root cause of errors. I had one more error, connected to Categories not being called with attributes, but for debug purposes I put empty array there - one error dissapeared, but that's it. I've also tried adding constructor to Categories and called super(), but did not help also.
I believe your issue is that you're exporting your Categories class twice, once connected, the other not.
If you remove export from export class Categories extends Component, does it work as expected?
When you're mapping the state in a component, you must access the desired variable through a reducer.
So instead of:
const mapStateToProps = state => ({
categories: state.categories
});
You must use:
const mapStateToProps = state => ({
categories: state.categories.categories
});
Your props don't have getCategories method, because you didn't pass it as a function to connect.
A better approach is to define only the action code in your actions file and then use mapDispatchToProps.
../../actions/categories.js
import axios from "axios";
export const getCategories = () => {
axios
.get("/api/notes/categories/")
.then(res => res.data);
})
.catch(err => console.log(err));
};
Categories.js
import { getCategories } from '../../actions/categories'
import { CATEGORIES_GET } from "./types";
const mapDispatchToProps = dispatch => {
return {
getCategories: () => dispatch(() => { type: CATEGORIES_GET, payload: getCategories() }),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Categories);