Redux, state not defined - reactjs

trying to make an option to change the color of text,border,background but i get the error state is not defined in the console.it says that state.options.text that i addressed in option page is not defined,
i checked the routing and it is Ok
option page
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import {textCH, borderCh, backgroundCh} from '../Utilities/options/theme'
function Options() {
const textcolor = useSelector((state)=>state.options.text)
console.log(textcolor);
return (
<div style={{ paddingLeft: '20px' }}>
<h1>OPTIONS</h1>
text color: <input type={'color'} />
border color: <input type={'color'} />
background color: <input type={'color'} />
</div>
)
}
export default Options
Reducer
import { createSlice } from '#reduxjs/toolkit'
const initialState = {
text:'#000000',
border:'#000000',
background:'#FFFFFF',
}
export const optionsSlice = createSlice({
name: 'options',
initialState,
reducers: {
textCH: (state,action) => {
state.text = action.payload
},
borderCh: (state,action) => {
state.border = action.payload
},
backgroundCh: (state, action) => {
state.background = action.payload
},
},
})
export const { textCH, borderCh, backgroundCh } = optionsSlice.actions
export default optionsSlice.reducer
Store file
import { configureStore } from '#reduxjs/toolkit'
import {optionsSlice} from './options/theme'
export const store = configureStore({
reducer: {
options: optionsSlice,
},
})
Console error:
Uncaught TypeError: state.options is undefined
textcolor Options.jsx:6
Provider setup:
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import {store} from "./Utilities/store";
import { Provider } from "react-redux";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<>
<Provider store={store}>
<App />
</Provider>
</>
);

You're importing the slice itself in the store.js, not reducer.
instead of calling the named function:
import {optionsSlice} from './options/theme'
we should call the default one:
import optionsSlice from './options/theme'

Related

How i can use useContext hook or just a Context in a middleware in the React-Redux app?

I had faced with a problem. The problem: I had tried to use context inside a middleware, but i`dont know how i can do it, because we can use useContext only in... 'Hooks can only be called inside of the body of a function component. Is it possible to use context inside the middleware? Thx for help!
'I have a context:
import { createContext, useState } from "react";
export const PopupContext = createContext();
export const PopupContextProvider = (props) => {
const [isShow, setIsShow] = useState(false);
return (<PopupContext.Provider
value={[isShow, setIsShow]}
>
{props.children}
</PopupContext.Provider>
)
}
my index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { Provider } from 'react-redux';
import store from './redux/store';
import { PopupContextProvider } from './context/popup/popup';
ReactDOM.render(
<React.StrictMode>
<PopupContextProvider>
<Provider store={store}>
<App />
</Provider>
</PopupContextProvider>
</React.StrictMode>,
document.getElementById('root')
);
and my store.js - it`s a Redux store, you know...
import { configureStore } from '#reduxjs/toolkit';
import alertMiddleware from '../middleware/alert.middleware';
import authReducer from './features/auth/auth-slice';
import cardReducer from './features/card/cardSlice';
const store = configureStore({
reducer: {
auth: authReducer,
card: cardReducer
},
middleware: getDefaultMiddleware => getDefaultMiddleware().concat(alertMiddleware)
})
export default store;
and my dumb middleware
import { PopupContext } from '../context/popup/popup';
import { useContext, useState } from 'react';
const alertMiddleware = store => next => action => {
const isShow = useContext(PopupContext);
if (action.type === 'auth/login/rejected') {
console.log(isShow);
}
console.log('middleware');
next(action)
}
export default alertMiddleware;
It's not. Hooks cant be used outside of components. You should send isShow as an action payload when you dispatch the action. Then you would have something like in your middleware
...
if (action.type === 'auth/login/rejected') {
console.log(action.payload.isShow);
}
...
Well, like i had understood, it's imposible to use context in your middleware (so sad). In this way, i had created a slice with reducers and etc. And now, a can take out all my logic in reducers, if someone doesn't know what is it... well, it's like a global state with services, which are available from all points in your application. The logic is: when some action type happen, the middleware handles it and dispatches some actions, in this action you can do everething, in my case i change the state and read this state from my functional component. I belive, what i had done a good explain.
Sequence of actions: some action => middleware => process action in reducer => change state
My middleware:
import { showPopup } from '../features/popup/popup-slice';
const POPUP_PROPERTIES = {
loginRejected: {
message: "LOGIN ERROR",
styles: {
color: "white",
backgroundColor: "red"
}
},
invalidateLoggedInUser: {
message: "You are logged out from your account",
styles: {
color: "white",
backgroundColor: "#4BE066"
}
},
cardCreateFulfilled: {
message: "Card set successfully created",
styles: {
color: "white",
backgroundColor: "#01C9F7"
}
},
cardDeleteFulfilled: {
message: "Card set successfully deleted",
styles: {
color: "white",
backgroundColor: "#4BE066"
}
}
}
const PopupMiddleware = ({ dispatch, getState }) => next => action => {
const { type } = action;
switch (type) {
case 'auth/login/rejected': {
dispatch(showPopup(POPUP_PROPERTIES.loginRejected));
break;
}
case 'auth/invalidateLoggedInUser': {
dispatch(showPopup(POPUP_PROPERTIES.invalidateLoggedInUser));
break;
}
case 'card/create/fulfilled': {
dispatch(showPopup(POPUP_PROPERTIES.cardCreateFulfilled));
break;
}
case 'card/delete/fulfilled': {
dispatch(showPopup(POPUP_PROPERTIES.cardDeleteFulfilled));
break;
}
default: break;
}
next(action);
}
export default PopupMiddleware;
My slice
import { createSlice, createAsyncThunk } from "#reduxjs/toolkit";
// -------------------------------------- Slice --------------------------------------
const initialState = {
popupEntity: {
message: null,
color: null,
},
isVisible: false
}
const popupSlice = createSlice({
name: 'popup',
initialState,
reducers: {
showPopup: {
reducer(state, action) {
state.popupEntity = action.payload;
state.isVisible = true;
}
},
hidePopup: {
reducer(state) {
state.isVisible = false;
}
}
},
})
export const { showPopup, hidePopup } = popupSlice.actions;
export default popupSlice.reducer;
// -------------------------------------- Selectors --------------------------------------
export const popupStateSelector = state => state.popup;
export const isVisibleSelector = state => state.popup.isVisible;
and store:
import { configureStore } from '#reduxjs/toolkit';
import PopupMiddleware from './middleware/popup.middleware';
import authReducer from './features/auth/auth-slice';
import cardReducer from './features/card/cardSlice';
import popupReducer from './features/popup/popup-slice';
const store = configureStore({
reducer: {
auth: authReducer,
card: cardReducer,
popup: popupReducer
},
middleware: getDefaultMiddleware => getDefaultMiddleware().concat(PopupMiddleware)
})
export default store;

TypeError: store.getState is not a function. (In 'store.getState()', 'store.getState' is undefined)

Hi guys i was setting up redux in my react native project but facing some issues while setup even though i am pretty sure i haven't used getState till now but as ssons as app runs i get error
TypeError: store.getState is not a function. (In 'store.getState()',
'store.getState' is undefined)
my code is as
reducers / hireducer.js
import { HI } from "../constants";
const initialState = {
count: 0,
};
const countReducer = (state = initialState, action) => {
switch (action.type) {
case HI:
return {
...state,
count: action.payload,
};
default:
return state;
}
};
export default countReducer;
reducers / index.js
import { combineReducers } from "redux";
import hiReducer from "./hireducer.js";
export default combineReducers({
hi: hiReducer,
});
store / configStore
import { createStore } from "redux";
import reducers from "../reducers/index";
const configureStore = () => {
return createStore(reducers);
};
export default configureStore;
App.js
import "react-native-gesture-handler";
import React from "react";
import { NavigationContainer } from "#react-navigation/native";
import AuthNavigator from "./navigations/AuthNavigation";
import { withHOC } from "./index.js";
function App() {
return (
<NavigationContainer>
<AuthNavigator />
</NavigationContainer>
);
}
export default withHOC(App);
index.js
import React from "react";
import { Provider } from "react-redux";
import configStore from "./redux/store/configStore";
export const withHOC = (App) => (props) => {
return (
<Provider store={configStore}>
<App {...props} />
</Provider>
);
};
even though if i normally wrap in without providing store i still get the same error
Your configStore returns a function instead of a store object.
So you rather call the function in your app like
<Provider store={configStore()}>
<App {...props} />
</Provider>
Or you create a store object from configStore like
const configureStore = () => {
return createStore(reducers);
};
export default configureStore();

Adding redux to react native?

i'm currently working on an app using react-native for the first time,
but i'm struggling to add redux.
i get this error TypeError: Cannot read property 'getState' of undefined and i don't know how to fix it.
this my code :
import React from "react";
import Home from "./home";
import { store } from "./redux/store";
import { Provider } from "react-redux";
/* #flow */
import { View, StyleSheet } from "react-native";
class App extends React.Component {
render() {
return (
<Provider store={store}>
<View style={styles.container}>
<Home />
</View>
</Provider>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
}
});
store.js :
import { applyMiddleware, createStore } from "redux";
import logger from "redux-logger";
import reducer from "./reducer";
const middlewares = [logger];
const store = createStore(reducer, applyMiddleware(...middlewares));
export default store;
reducer.js :
import { combineReducers } from "redux";
import mapReducer from "../redux/maps/maps-reducer";
export default combineReducers({
map: mapReducer
});
maps-action.js:
import MAPSActionTypes from './maps-action-types';
export const currentlocation = () => ({
console.log(${location});
type : MAPSActionTypes.GET_CURRENT_LOCATION
});
maps-reducer.js:
import MAPSActionTypes from "./mapsactiontypes";
const INITIAL_STATE = {
location: {}
};
const mapReducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
case MAPSActionTypes.GET_CURRENT_LOCATION:
return {
...state,
location: action.payload
};
default:
return state;
}
}
export default mapReducer;
home.js:
import React from 'react';
import {
StyleSheet,
View,
Text,
} from 'react-native';
import {connect} from 'react-redux'
const Home = (props) => {
return (
<View style={styles.container}>
<Text>welcome</Text>
<Text>{props.location}</Text>
</View>
);
};
const styles = StyleSheet.create({
container:{
flex:1,
justifyContent:'center',
alignItems:'center'
}
});
const mapStateToProps = (state) => {
return {
location: state.map.location
}
}
export default connect(mapStateToProps)(Home);
i'm all ears from more clarification or more details.
i will be very thankful if there's anyone who can help me to fix that problem.
The problem is you export default in store.js file.
export default store;
But in App you import it with {}. So the store you imported is undefined.
import { store } from "./redux/store";
The correct import is
import store from "./redux/store";

Redux component did not re-render after state is reduced

I have an issue that is the component did not re-render after action is dispatched. Even in the redux dev tool. The action and state are working as expected. But, it(App.js) just won't re-render(after action DATE_ClickChange is triggered).
Following are the codes. Please help me with this issue. Thank you.
This is index.js
import React, { Component } from "react";
import ReactDOM from "react-dom";
import "./index.scss";
import "bootstrap/dist/css/bootstrap.min.css";
import App from "./components/App/App";
import { Provider } from "react-redux";
import store from "./store";
class Index extends Component {
render() {
return (
<Provider store={store}>
<div className="indexStyle">
<App />
</div>
</Provider>
);
}
}
ReactDOM.render(<Index />, document.getElementById("index"));
store.js
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import rootReducer from "./reducers/rootReducer";
const initialState = {};
const middleware = [thunk];
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
export default store;
rootReducer.js
import { combineReducers } from "redux";
import weatherReducer from "./weatherReducer";
import dateReducer from "./dateReducer";
export default combineReducers({
weatherData: weatherReducer,
dateData: dateReducer
});
dateReducer.js
import { DATE_HandlChange, DATE_ClickChange } from "../actions/types";
import moment from "moment";
const initialState = {
startDate: moment()
};
export default (state = initialState, action) => {
switch (action.type) {
case DATE_HandlChange:
return {
startDate: action.payload.startDate
};
case DATE_ClickChange:
return {
...state,
startDate: action.payload.startDate
};
default:
return state;
}
};
dateAction
import { DATE_HandlChange, DATE_ClickChange } from "./types";
export const dateHandleChange = date => dispatch => {
dispatch({
type: DATE_HandlChange,
payload: {
startDate: date
}
});
};
export const dateClickChange = number => (dispatch, getState) => {
dispatch({
type: DATE_ClickChange,
payload: {
startDate: getState().dateData.startDate.add(number, "d")
}
});
};
App.js
import React, { Component } from "react";
import "./app.scss";
import "react-datepicker/dist/react-datepicker.css";
import DatePicker from "react-datepicker";
import { Button } from "reactstrap";
import Content from "../Content/Content";
import { connect } from "react-redux";
import {
dateHandleChange,
dateClickChange } from "../../actions/dateAction";
class App extends Component {
render() {
return (
<div className="mainPanel">
<div className="datePanel">
<Button
outline
onClick={() => this.clickChange(-1)}
color="info"
className="prevDate"
size="md"
>
Previous
</Button>
<DatePicker
dateFormat="YYYY/MM/DD"
selected={this.props.dateData}
onChange={date => this.props.dateHandleChange(date)}
className="dateInput"
/>
<Button
outline
onClick={() => this.props.dateClickChange(1)}
color="info"
className="nextDate"
size="md"
>
Next
</Button>
</div>
<Content />
</div>
);
}
}
const mapStateToProps = state => ({
dateData: state.dateData.startDate
});
export default connect(
mapStateToProps,
{ dateHandleChange, dateClickChange }
)(App);
I'm not completely sure here but it seems like you're modifying the state directly with this code startDate: getState().dateData.startDate.add(number, "d")
getState() doesn't return a copy of the state as far as I know. This means that you have to make a copy of it first. Thats probably why it won't re-render. Redux don't re-render when you modify the state directly. You should never modify the state directly. Treat it as immutable and make a copy first and don't mutate the state. =)

getting error "Expected the reducer to be a function."?

I am getting error "Expected the reducer to be a function.".
I am trying to add redux in my project .I create reducer but also getting error "Expected the reducer to be a function." .here is my code
https://codesandbox.io/s/k5Gp2gglx
import React from 'react';
import { render } from 'react-dom';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import {Provider} from 'react-redux';
import {combindReducer} from './reducers/index'
import Hello from './Hello';
const styles = {
fontFamily: 'sans-serif',
textAlign: 'center',
};
const App = () => (
<div style={styles}>
<Hello name="CodeSandbox" />
<h2>Start editing to see some magic happen {'\u2728'}</h2>
</div>
);
const store = createStore(combindReducer,
applyMiddleware(thunk)
);
render(
<Provider store ={store}>
<App />
</Provider>
, document.getElementById('root'));
combine reducer
import {combineReducers } from 'redux';
import {first_redux} from './topstories';
const combindReducer = combineReducers({
item: first_redux
})
export default combindReducer;
topstories
export default function(state = [], action) {
switch (action.type) {
case 'ADD_ITEM':
return [
...state,
action.payload
];
case 'DELETE_ITEM':
const index = state.indexOf(action.payload);
if (index === -1) {
return state;
}
return state.slice(0, index).concat(state.slice(index + 1));
case 'UPDATE_ITEM':
let newList = state.slice()
newList.splice(action.payload.index, 1, action.payload.item)
return newList;
default:
return state
}
}
since you're using default exports (not named exports), the import statements for your reducers should not have curly braces:
import combindReducer from './reducers/index';
and
import first_redux from './topstories';
https://codesandbox.io/s/L8RE3X5D4

Resources