I'm stuck and I can't find out how to store a dictionary in Redux State.
const productinuse = (state = [], action) => {
switch (action.type) {
case 'productinuse':
return [...state, action.payload];
default:
return state;
}
};
export default productinuse;
animModal(product) {
console.log(product);
() =>
store.dispatch({
type: 'productinuse',
payload: product,
}),
store.dispatch({type: 'toggleproductmodal'});
}
Example of the dictionary that I'm trying to store on it :
{"UNIT": "Kg", "images": ["https://example.com/image.jpg"], "module_id": "1", "product_id": "6", "product_img": "example.com/image2.js", "product_name": "Ananas", "product_prix": "8.5", "product_text": "1 Kg Ananas."}
I always get the default empty array as a value.
EDIT
const initialState = {
productinuse: [],
};
const productinuse = (state = initialState, action) => {
console.log(action.payload + 'DEBUGGINS');
switch (action.type) {
case 'productinuse':
return Object.assign({}, state, {
productinuse: [...state, action.payload],
});
default:
return state;
}
};
export default productinuse;
**EDIT 2 **
<TouchableOpacity
key={product.product_id}
style={{width: '50%', position: 'relative'}}
onPress={() =>
this.setState(
{
product: product,
},
(product) =>
store.dispatch({
type: 'productinuse',
payload: product,
}),
() => store.dispatch({type: 'toggleproductmodal'})}>
Now When I perform the action I'm getting a TypeError: Invalid attempt to spread non-iterable instance.
In order to be iterable, non-array objects must have a Symbol.iterator method.
try this:
state:
const initialState = {
productinuse: []
}
reducer:
const productinuse = (state = initialState, action) => {
switch (action.type) {
case 'productinuse':
return Object.assign({}, state, {
productinuse: [...state.productinuse, action.payload],
});
default:
return state;
}
};
export default productinuse;
Related
I currently started learning redux. My code was working perfectly with core redux, then I tried out #reduxjs/toolkit and now I'm unable to access the function to change the state in the store. Here is my code of reducer.
const seasonEdits = createSlice({
name: "seasons",
initialState: [],
reducers: {
addSeason(state, action) {
state.push(action.payload);
console.log("this here");
},
removeSeason(state, action) {
state.filter((season) => season.id !== action.payload);
},
markComplete(state, action) {
state.map((season) => {
if (season.id == action.payload) season.isWatched = !season.isWatched;
});
},
},
});
export const { addSeason, removeSeason, markComplete } = seasonEdits.actions;
export default seasonEdits.reducer;
and my store.js file
import { configureStore } from "#reduxjs/toolkit";
import seasonReducer from "./reducer";
export default store = configureStore({
reducer: {
seasons: seasonReducer,
},
});
and the add.js file which has add functionality. Calling a handleSubmit function which is creating an object and adding it to an array which is the state in store.
const handleSubmit = async () => {
try {
if (!name || !totalNoSeason) {
return alert("Please add both fields");
}
const seasonToAdd = {
id: shortid.generate(),
name,
totalNoSeason,
isWatched: false,
};
addSeason(seasonToAdd);
navigation.navigate("Home");
} catch (error) {
console.log(error);
}
};
const mapDispatchToProps = (dispatch) => {
return {
addSeason: (data) => dispatch(addSeason(data)),
};
};
Add.propTypes = {
addSeason: propTypes.func.isRequired,
};
export default connect(null, mapDispatchToProps)(Add);
The issue is that array.map() and array.filter() return new arrays! Right now your reducers are calling those functions, and then just throwing away the new arrays:
removeSeason(state, action) {
// The return value is thrown away and ignored!
state.filter((season) => season.id !== action.payload);
},
You need to return the new value:
removeSeason(state, action) {
// Now RTK will see the new return value
return state.filter((season) => season.id !== action.payload);
},
See https://redux-toolkit.js.org/usage/immer-reducers#resetting-and-replacing-state for more details.
My state in redux is coming undefined and I don't know why
my Actions:
export function AddToLoginData(LoginData: any) {
return {
type: ActionTypes.DataAdd,
payload: LoginData,
}
}
export function InitialState() {
return {
type: ActionTypes.DataInitialState,
}
}
my Reducer:
const dataUser = (state = [], action: {type: string, payload: any}) => {
switch(action.type) {
case ActionsTypes.DataAdd:
return action.payload;
case ActionsTypes.DataInitialState:
return []
default:
return state;
}
}
export default dataUser;
Where i'm putting to perform the action:
if (Math.floor(Response.status / 100) === 2) {
dispatch(Actions.LoginData.AddToLoginData(Response.data))
I have a simple question. I am implementing the useSelector Hook React Native together with ReduxToolKit.
But now the problem when the useSelector have data or not empty and everytime I change my screen the useSelector data remain the same data.
I want when change screen my useSelector data to be empty array again.
How do I solve this problem ?
Thank You
EDIT :
ApiChartingSlice.js
export const ApiChartingDataThunk = createAsyncThunk(
'ApiChartingData',
async (data) => {
try {
const {chart, ticker} = data;
const response = await ApiChartingData(chart, ticker);
return response;
} catch (error) {
return console.log({ error: error.message });
}
}
)
// status: 'idle' | 'loading' | 'succeeded' | 'failed',
export const ApiChartingDataSlice = createSlice({
name: 'ApiChartingData',
initialState: {
apiData: [],
status: 'idle',
error: null
},
reducers: {},
extraReducers: {
[ApiChartingDataThunk.pending.type]: (state, action) => {
state.playerList = {
status: state.status = 'loading',
apiData: [],
error: {},
};
},
[ApiChartingDataThunk.fulfilled.type]: (state, action) => {
state.playerList = {
status: state.status = 'idle',
apiData: state.apiData = action.payload,
error: {},
};
},
[ApiChartingDataThunk.rejected.type]: (state, action) => {
state.playerList = {
status: state.status = 'failed',
apiData: [],
error: action.payload,
};
},
}
});
ChartUserCard.js
const tickerData = useSelector(state => state.ApiTicker.apiData);
const checkTicker = useCallback(() => {
dispatch(ApiTickerThunk(inputValue))
.unwrap()
.then((originalPromiseResult) => {
// console.log(originalPromiseResult);
})
.catch((rejectedValueOrSerializedError) => {
console.log(rejectedValueOrSerializedError);
});
setStart(true);
}, [dispatch, inputValue, tickerData]);
in Here : const tickerData = useSelector(state => state.ApiTicker.apiData);
I want to reset tickerData.
Thank To #this.arjun.
const dataThunk = {chart: "", ticker: ""};
const tickerThunk = "";
const resetDataThunk = useCallback(() => {
dispatch(ApiTickerThunk(tickerThunk));
dispatch(ApiChartingDataThunk(dataThunk));
}, [dispatch]);
Just use dispatch empty data.
I have state that looks following:
const initialState = {
employee: '',
companyNumber: '',
insuranceCompany: '',
workHealthcare: '',
actionGuide: '',
}
And I have screen where I want to update/edit these values.
And the updated values are shown here in this screen.
this is my action file:
const UPDATE_EMPLOYEE_DETAILS = 'UPDATE_EMPLOYEE_DETAILS'
const UPDATE_COMPANYNUMBER_DETAILS = 'UPDATE_COMPANYNUMBER_DETAILS'
const UPDATE_INSURANCECOMPANY_DETAILS = 'UPDATE_INSURANCECOMPANY_DETAILS'
const UPDATE_WORKHEALTHCARE_DETAILS = 'UPDATE_WORKHEALTHCARE_DETAILS'
const UPDATE_ACTIONGUIDE_DETAILS = 'UPDATE_ACTIONGUIDE_DETAILS'
export const employeeEditAction = (text) => ({
type: UPDATE_EMPLOYEE_DETAILS,
payload: { employee: text },
})
export const companyNumberEditAction = (text) => ({
type: UPDATE_COMPANYNUMBER_DETAILS,
payload: { companyNumber: text },
})
export const insuranceCompanyEditAction = (text) => ({
type: UPDATE_INSURANCECOMPANY_DETAILS,
payload: { insuranceCompany: text },
})
export const workHealthcareEditAction = (text) => ({
type: UPDATE_WORKHEALTHCARE_DETAILS,
payload: { workHealthcare: text },
})
export const actionGuideEditAction = (text) => ({
type: UPDATE_ACTIONGUIDE_DETAILS,
payload: { actionGuide: text },
})
and this is the reducer file.
const UPDATE_WORKPLACE_DETAILS = 'UPDATE_WORKPLACE_DETAILS'
const initialState = {
employee: '',
companyNumber: '',
insuranceCompany: '',
workHealthcare: '',
actionGuide: '',
}
const workplaceValueReducer = (state = initialState, action) => {
switch (action.type) {
case UPDATE_WORKPLACE_DETAILS:
return {
...state,
employee: action.payload.employee,
companyNumber: action.payload.companyNumber,
insuranceCompany: action.payload.insuranceCompany,
workHealthcare: action.payload.workHealthcare,
actionGuide: action.payload.actionGuide
}
default:
return state
}
}
export default workplaceValueReducer
This is the screen and the function that should save the edited values.
const saveWorkPlaceDetails = () => {
if (employee.length > 0) {
// props.editWorkplaceDetails(
// employee,
// companyNumber,
// insuranceCompany,
// workHealthcare,
// info,
// )
props.saveEmployee(employee)
props.saveCompanyNumber(companyNumber)
props.saveInsuranceCompany(insuranceCompany)
props.saveWorkHealthcare(workHealthcare)
props.saveActionGuide(info)
setEmployee('')
setCompanyNumber('')
setInsuranceCompany('')
setWorkHealthcare('')
setInfo('')
workDetailsSavedToast()
} else {
workDetailsErrorToast()
}
}
const mapDispatchToProps = (dispatch) => ({
//editWorkplaceDetails: bindActionCreators(, dispatch),
saveEmployee: (text) => dispatch(employeeEditAction(text)),
saveCompanyNumber: (text) => dispatch(companyNumberEditAction(text)),
saveInsuranceCompany: (text) => dispatch(insuranceCompanyEditAction(text)),
saveWorkHealthcare: (text) => dispatch(workHealthcareEditAction(text)),
saveActionGuide: (text) => dispatch(actionGuideEditAction(text)),
})
export default connect(null, mapDispatchToProps)(EditWorkplaceDetails)
The input fields looks as following:
<Input
style={inputLicenseEdit}
inputContainerStyle={{
borderBottomColor: colors.white,
width: '100%',
}}
placeholder='Tyƶnantaja'
placeholderTextColor={colors.white}
leftIcon={
<Ionicons name='ios-person-outline' size={30} color={colors.white} />
}
onChangeText={(text) => {
setEmployee(text)
}}
/>[![enter image description here][1]][1]
Currently when I try to update the items in the state it doesn't update and triggers the error toast instead.
What do I need to change here?
You should set as many case in your reducer switch that you have actions' consts.
Example for one action :
export const UPDATE_EMPLOYEE_DETAILS = 'UPDATE_EMPLOYEE_DETAILS'
export const employeeEditAction = (employee) => ({
type: UPDATE_EMPLOYEE_DETAILS,
employee,
})
import {UPDATE_EMPLOYEE_DETAILS, /** ... other actions */} from 'action path';
const workplaceValueReducer = (state = initialState, action) => {
switch (action.type) {
case UPDATE_EMPLOYEE_DETAILS:
return {
...state,
employee: action.employee
}
// ... other cases
default:
return state
}
}
It looks like you update all your workplace's values at the same time, so you should simply do :
export const UPDATE_WORKPLACE_DETAILS = 'UPDATE_WORKPLACE_DETAILS'
export const updateWorkPlaceDetailsAction = (details) => ({
type: UPDATE_WORKPLACE_DETAILS,
details,
})
import {UPDATE_WORKPLACE_DETAILS} from 'action path';
const workplaceValueReducer = (state = initialState, action) => {
switch (action.type) {
case UPDATE_WORKPLACE_DETAILS:
return action.details || state;
default:
return state
}
}
I personnaly set both cases, so one action for the whole object, plus one action foreach object's attributes I want to update
PS : write "js" after your first line backticks block to get code colors
"What if I want to have the cars listed under certain user like this. user: {cars: [{}]}"
(Replied in previous answered)
It depends of what you want to do.
Examples :
// state is your user
const userReducer = (state = initialState, action) => {
switch (action.type) {
case ADD_CAR:
const nextState = {
...state,
cars: state.cars.slice() // copy array, because all children that ara objects and arrays, should be immutable too
};
return nextState;
newtState.cars.push(action.car);
/** can be done like that too, but it consume more performance */
return {
...state,
cars: [...state.cars, action.car]
}
case UPDATE_CAR:
const nextState = {
...state,
cars: state.cars.slice();
};
nextState.cars[action.index] = action.car;
/** OR even : */
nextState.cars[action.index] = {...state.cars[action.index], [action.key]: action.value}
return nextState;
case REMOVE_CAR:
const nextState = {
...state,
cars: state.cars.slice()
};
// do not use splice before copying the array and do not return directly splice
newtState.cars.splice(action.index, 1);
return nextState;
default:
return state
}
}
see documentation for slice and splice
My Redux thunk dispatch was working until i made a single API call but stopped working after using combineReducers for multiple api calls.
This is my component code :
const mapStateToProps = state => ({
loading: state.loading,
data: state.data,
error: state.error,
networkError: state.networkError
})
const mapDispatchToProps = {
login
}
These are my Actions :
export const GET_LOGIN_LOADING = "GET_LOGIN_LOADING"
export const GET_LOGIN_SUCCESS = "GET_LOGIN_SUCCESS"
export const GET_LOGIN_ERROR = "GET_LOGIN_ERROR"
export const GET_REGISTER_LOADING = "GET_REGISTER_LOADING"
export const GET_REGISTER_SUCCESS = "GET_REGISTER_SUCCESS"
export const GET_REGISTER_ERROR = "GET_REGISTER_ERROR"
This is my reducer for login and register actions :
import * as Actions from './Actions'
const loginState = {
loginLoading: false,
loginData: [],
loginError: '',
}
const registerState = {
registerLoading: false,
registerData: [],
registerError: '',
}
export const loginReducer = (state = { loginState }, action) => {
switch (action.type) {
case Actions.GET_LOGIN_LOADING:
return {
...state,
loginLoading: action.payload
}
case Actions.GET_LOGIN_SUCCESS:
return {
...state,
loginData: action.payload,
loginLoading: false,
}
case Actions.GET_LOGIN_ERROR:
return {
...state,
loginError: action.payload,
loginLoading: false,
}
default: return loginState
}
}
export const registerReducer = (state = { registerState }, action) => {
switch (action.type) {
case Actions.GET_REGISTER_LOADING:
return {
...state,
registerLoading: action.payload
}
case Actions.GET_REGISTER_SUCCESS:
return {
...state,
registerData: action.payload,
registerLoading: false,
}
case Actions.GET_REGISTER_ERROR:
return {
...state,
registerError: action.payload,
registerLoading: false,
}
default: return registerState
}
}
My Redux Store Code :
import { createStore, applyMiddleware, combineReducers } from 'redux'
import thunk from 'redux-thunk'
import{ loginReducer, registerReducer } from '../redux/Reducer'
const reducer = combineReducers({loginReducer, registerReducer})
export default createStore(reducer, applyMiddleware(thunk))
Finally my thunk code used for making API calls :
export const login = (countryCode, phone, password) => {
const userName = {
countryCode,
phone
}
return dispatch => {
dispatch(getLoginLoading(true))
service.post('login', {
userName,
password
})
.then(response => {
console.log(response.data)
dispatch(getLoginSuccess(response.data))
})
.catch(error => {
console.log(error)
dispatch(getLoginError(error.response.data))
})
}
}
export const register = (name, countryCode, phone) => {
return dispatch => {
dispatch(getRegisterLoading(true))
service.post('register', {
name,
countryCode,
phone,
})
.then(response => {
console.log(response.data)
dispatch(getRegisterSuccess(response.data))
})
.catch(error => {
console.log(error.response)
dispatch(getRegisterError(error.response))
})
}
}
Finally found an answer by myself. When you are use combine reducers, Redux creates a nested state object for each reducer, Hence when accessing the state you should use :
const reducer = combineReducers({loginReducer, registerReducer})
const mapStateToProps = state => ({
loading: state.loginReducer.loading,
data: state.loginReducer.data,
error: state.loginReducer.error,
networkError: state.loginReducer.networkError
})