Reputation: 71
I would like to save object data inside my array state. But when I try to call an action in reducer, the INITIAL_STATE.highlightedVerse always resulted as undefined when I tried to console.log() it. It should be an empty array, not undefined.
These are the dependencies that I used in package.json Expo v32.0.0, React v16.5.0, Redux v4.0.1, React Redux v5.1.1, Redux Persist v.5.10.0
These are the code that I wrote:
import {
ADD_BIBLE_VERSE_HIGHLIGHT,
REMOVE_BIBLE_VERSE_HIGHLIGHT,
} from 'ndc-ministry/redux/actions/types'
const INITIAL_STATE = {
highlightedVerse: [],
}
const reducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
case ADD_BIBLE_VERSE_HIGHLIGHT:
const currentHighlightedVerse = state.highlightedVerse
if(currentHighlightedVerse.length > 0){
currentHighlightedVerse.forEach(obj => {
if(action.payload.bookIndex == obj.bookIndex
&& action.payload.chapterIndex == obj.chapterIndex
&& action.payload.verseIndex == obj.verseIndex
) {
return {...state}
}
})
}
return {
...state,
highlightedVerse: [...state.highlightedVerse, action.payload]
}
case REMOVE_BIBLE_VERSE_HIGHLIGHT:
const deletedHighlightVerse = state.highlightedVerse.filter(obj => JSON.stringify(action.payload) != JSON.stringify(obj))
return {
...state,
highlightedVerse: deletedHighlightVerse
}
default:
return state
}
}
export default reducer
In development mode, it works just fine. But when I updated it to production APK/IPA, it always returns undefined and I have no idea how. I already tried to search for two days but still could not understand why.
Thank you for reading this issue and I hope someone could help me on this :)
Upvotes: 2
Views: 2630
Reputation: 88
I would say simplify your reducer and remove the highlightedVerse
field.
And then treat your state like the Array it is instead of an Array of an Object.
So change from {}
to []
where applicable.
For example (and without testing):
import {
ADD_BIBLE_VERSE_HIGHLIGHT,
REMOVE_BIBLE_VERSE_HIGHLIGHT,
} from 'ndc-ministry/redux/actions/types'
const INITIAL_STATE = [];
const reducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
case ADD_BIBLE_VERSE_HIGHLIGHT:
const currentHighlightedVerse = [...state];
if(currentHighlightedVerse.length > 0){
currentHighlightedVerse.forEach(obj => {
if(action.payload.bookIndex == obj.bookIndex
&& action.payload.chapterIndex == obj.chapterIndex
&& action.payload.verseIndex == obj.verseIndex
) {
return state;
}
})
}
return [...state, action.payload];
case REMOVE_BIBLE_VERSE_HIGHLIGHT:
const deletedHighlightVerse = state.filter(obj => JSON.stringify(action.payload) != JSON.stringify(obj))
return deletedHighlightVerse;
default:
return state
}
}
export default reducer
This way in your initialState for your store... your highlightedVerse
field can be an empty array and you can set this reducer as the reducer for that field.
Good luck.
Upvotes: 0
Reputation: 15166
I think you have an issue in mapStateToProps
function. If you change it to have the state object (BibleReducer) without destructuring assignment in the function's parameter list then you will have the value in hightlightedVerse property as needed.
You can check the value by debugging or doing console.log(BibleReducer)
to test where and how your variable's value show up in the code.
Original one - from your code with destructuring the value is undefined:
function mapStateToProps({BibleReducer}) {
console.log(BibleReducer);
return {
highlightedVerse: BibleReducer.highlightedVerse,
}
}
I guess the working one - you should have the state object:
function mapStateToProps(BibleReducer) {
console.log(BibleReducer);
return {
highlightedVerse: BibleReducer.highlightedVerse,
}
}
Please read further about destructuring assignment here.
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
With destructuring you are referencing to state.BibleReducer.highlightedVerse
property and I think that is why the value is showed as undefined.
Let me know if this works or not, we can think further if needed.
UPDATE:
If you would like to use still destructuring assigment then you can go for the following solution to use only highlightedVerse
array value:
function mapStateToProps({highlightedVerse}) {
console.log(highlightedVerse);
return {
highlightedVerse: highlightedVerse,
}
}
Thanks @Clarity for the idea!
Upvotes: 1
Reputation: 71
Thank you @Clarity @Yossi @Domino987
Here is my store/index.js
import { AsyncStorage } from 'react-native'
import storage from 'redux-persist/lib/storage'
import { createStore } from 'redux'
import { persistStore, persistReducer } from 'redux-persist'
import reducers from 'ndc-ministry/redux/reducers'
const persistConfig = {
key: 'root',
storage: AsyncStorage
}
const persistedReducer = persistReducer(persistConfig, reducers)
export const store = createStore(
persistedReducer,
)
export const persistor = persistStore(store)
The weird thing is, every state in my redux is stored & persisted WELL, except when the state is an array. This is how I dispatch my action in the React component
import { addBibleVerseHighlight } from 'project-name/redux/actions'
class BibleScreen extends Component {
addHighlight = () => {
this.state.selectedVersesIndex.map((value) => {
const verseData = {
bookIndex: this.props.selectedBookIndex,
chapterIndex: this.props.selectedChapterIndex,
verseIndex: value,
}
this.props.addBibleVerseHighlight(verseData)
})
}
render() { ... }
}
function mapStateToProps({BibleReducer}) {
return {
highlightedVerse: BibleReducer.highlightedVerse,
}
}
const mapDispatchToProps = {
addBibleVerseHighlight,
removeBibleVerseHighlight,
}
export default connect(mapStateToProps, mapDispatchToProps)(BibleScreen)
Upvotes: 0