Using dispatched actions - react-native

I have this on the bottom of my main file:
export default connect(state => ({
state: state.firebaseReducer
}),
(dispatch) => ({
actions: bindActionCreators(firebaseActions, dispatch)
})
)(Routing);
And this is my reducer that I imported
const initialState = null;
export function firebaseRef(state = initialState, action) {
switch (action.type) {
case 'FIREBASE_REF_SET':
return action.value;
default:
return state;
}
}
Action:
export function setFirebaseRef(ref) {
return {
type: 'FIREBASE_REF_SET',
value: ref
};
}
But when I try to do this in my main file:
componentDidMount() {
state.setFirebaseRef(ref);
}
It says "Can't find variable: state" . Am I calling it the wrong way? I want to be able to call the setFireBaseRef action.

connect injects parts of state and dispatch into props. You want to dispatch the action using:
this.props.dispatch(setFireBaseRef(ref))
Or, assuming firebaseActionscontains setFireBaseRef, you can just do:
this.props.actions.setFireBaseRef(ref)

Related

Reducer gives an invalid attempt spread non-iterable instance

Would like to know whats wrong with my code it gives an error when i try dispatching a action using redux this is my reducer.js code
import {UPDATE_LOGIN} from './constants'
const initialState = {
isLogged:false
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case UPDATE_LOGIN:
return [
...state,
{
isLogged:action.isLogged
}
];
default:
return state;
}
}
export default reducer;
it gives a Invalid attempt to spread non-iterable instance.
In order to be iterable, non-array objects must have a Symbol.iterator method.
Your state is an object, and you try to destructure it as an array. In addition, you try to include the object, instead of changing the property. Try this:
const reducer = (state = initialState, action) => {
switch (action.type) {
case UPDATE_LOGIN:
return {
...state,
isLogged: action.isLogged
};
default:
return state;
}
}

mapStateToProps called but not calling componentWillRecieveProps when state has same value

I have the following reducer:
export default function UserReducer(state = initialState, action){
let nextState;
switch(action.type){
case USER_RECOVERY_CODE_VALIDATED:
nextState = {
...state,
recoverycodevalidated : action.payload.recoverycodevalidated
}
return nextState;
default:
return state;
}
}
And my component is connected to the store that way:
function mapStateToProps(state) {
console.log("updated");
return { recoverycodevalidated: state.user.recoverycodevalidated };
}
export default connect(mapStateToProps)(ResetPasswordCodeScreen)
And when the props change thanks to the mapStateToProps function, I redirect the user to the next screen:
async componentWillReceiveProps(newProps){
console.log("updated props");
if(newProps.recoverycodevalidated){
this.props.navigation.navigate("ResetPasswordFinal", { userId: this.props.navigation.state.params.userId});
}
}
The problem is that when the state is updated the first time and the value of recoverycodevalidated is set in the props, the second time if the value of the variable is the same, the props are not updated because the method componentWillRecieveProps is not fired, eventhough the mapStateToProps is fired everytime. What I'm doing wrong ?
Try using componentDidUpdate instead
componentDidUpdate(prevProps) {
console.log("updated props");
if (prevProps.recoverycodevalidated) {
this.props.navigation.navigate("ResetPasswordFinal", { userId:
this.props.navigation.state.params.userId});
}
}

Unable to get payload from action in reducer inside react native app?

I am trying to get a json response from an api and get the data successfully but when I call a action within another action using redux-thunk, my data is not available inside the reducer. I need data in "data" property inside my reducer get in component. Check the code below.
This is my action
import { GET_REPORT, GET_DATA_SUCCESS } from './types';
export const getData = (text) => {
return (dispatch) => {
dispatch ({ type: GET_REPORT})
fetch('http://api.openweathermap.org/data/2.5/forecast?q='+text+'&cnt=1&units=metric&APPID={key}')
.then(response => response.json())
.then(data => getDataSuccess(dispatch, data.list[0]))
.catch((error) => console.log(error));
};
};
const getDataSuccess = (dispatch, data) => {
//console.log(data);
dispatch({
type: GET_DATA_SUCCESS,
payload: data
});
}
this is my reducer
import { GET_REPORT } from'../actions/types';
const INITIAL_STATE = {
data: '',
}
export default (state = INITIAL_STATE, action) => {
switch(action.type){
case GET_REPORT:
console.log(action.payload); // getting undefined
return {...state, data: action.payload};
default:
return state;
}
}
I need data in "data" property get in component.
you are missing GET_DATA_SUCCESS in your reducer
The action dispatch ({ type: GET_REPORT}) , doesn't contain a payload hence undefined. Either you need to make reducer to handle action GET_DATA_SUCCESS or modify the existing one.
To simplify, dispatch({
type: GET_DATA_SUCCESS,
payload: data
}); contains a payload whereas dispatch ({ type: GET_REPORT}) doesn't
Resolved it by adding new switch case for GET_DATA_SUCCESS and get the payload from getDataSuccess and removing the payload from GET_REPORT case.
Now switch case looks like this
switch(action.type){
case GET_REPORT:
return {...state};
case GET_DATA_SUCCESS:
console.log(action.payload);
return{...state, data: action.payload}
default:
return state;
}

how to `bindActionCreators` with redux-thunk

I am quite new to JavaScript and react-native and I have existing project that I need to add functionality to. It is using redux and redux-thunk with redux-saga to send API requests. Currently it supports only 1 dispatch function per component and I need to dispatch several types of requests to the saga. I am trying to bindActionCreators to add the dispatch to the stores but to no avail.. I am totally lost on the mapDispatchToProps part and how do I "fire the action" afterwards..
in single dispatch to props, I did this:
let sdtp = (arg) => {
return (dispatch) => {
dispatch({
type: 'GET_TEST_HASHMAP_SAGA',
hashmap: arg
})
}
}
export default MainPage = connect(
mapStateToProps,
{ sdtp }
)(MainPage);
and I can "access the function" (is this the right term? at least my saga gets called) inside the MainPage.render() component :
`this.props.sdtp({'hello':'world'});`
but when I change to use bindActionCreators, I cannot access it in the props anymore (I have tried so many different experiments I almost give up)
Here is how I construct my multiple dispatches:
let action1 = (args) => {
return (dispatch) => {
dispatch({
type: 'GET_TEST_HASHMAP_SAGA',
hashmap: arg
});
}
}
let action2 = (args) => {
return (dispatch) => {
dispatch({
type: 'GET_TEST_HASHMAP_SAGA2',
params: arg
});
}
}
let action3 = (args) => {
return (dispatch) => {
dispatch({
type: 'GET_TEST_HASHMAP_SAGA3',
args: arg
});
}
}
let mdtp = (dispatch) => {
return {
actions: bindActionCreators(action1, action2, action3, dispatch)
}
}
export default MainPage = connect(
mapStateToProps,
{ mdtp }
)(MainPage);
I am trying to access the actions like this:
this.props.mdtp.action1({arg: 'hello'});
Thanks in advance!
connect takes four arguments...most people usually only need the first two.
mapStateToProps you have, and I'm assuming it's a function.
mapDispatchToProps is the second...the issue is there.
bindActionCreators is nothing but a for loop...leave it out and you will better understand what is happening.
Try this:
function mapDispatchToProps(dispatch) {
return {
action1: (args) => dispatch(action1(args)),
action2: (args) => dispatch(action2(args)),
}
}
export default MainPageContainer = connect(
mapStateToProps,
mapDispatchToProps
)(MainPage)
And call them as
this.props.action1(args) and this.props.action2(args)
If you insist on using the overrated bindActionCreators the syntax would be:
function mapDispatchToProps(dispatch){
return {
actions: bindActionCreators({
action1,
action2,
}, dispatch)
}
}
Also, use const instead of let since you are not redefining the value. It is also best to export the connected component under a different name than the class name of the component.
In your mpdt function, you need to return result of bindActionCreators call, not object with action key.
So, it should be
const mdtp = (dispatch) => {
return bindActionCreators({
action1, action2, action3
}, dispatch);
};
and you can call them as this.props.action1(...)
From your code it also seems, that you have confused two ways of passing action creators to the component. One way is described above. And another way, you can pass your action creators directly to connect() using object notations, like so
export default MainPage = connect(
mapStateToProps,
{ action1, action2, action3 }
)(MainPage);
which will have same result. And your first approach, with sdtp action creator uses this approach.
Alternatively, you can also skip mapDispatchToProps entirely..
Within your render() function, you can just call dispatch directly like this:
this.props.dispatch({type: 'GET_TEST_HASHMAP_SAGA2', params: {"hello": "world"}});
Then in your connect function, you can skip the mapDispatchToProps param entirely.
export default MainPage = connect(
mapStateToProps
)(MainPage);
I know this isn't the answer, but this is just an alternative that works as well

Duplicate items on redux state tree

I am trying to update my Redux state with a toggle button. My LB reducer is comprised of 2 reducers, an array called listItems for displaying a unique number of values, and filterBarState which is used as a reference to the current filters.
While my initial state is correct, my reducer places the toggle action outside of filterBarState
Below is my LB object reducer
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case EVENT_FILTER_PRESSED:
return {
// Reducer composition
filterBarState: eventFilter(state.filterBarState, action),
listItems: eventItems(state.listItems, action)
};
case MALE_FILTER_PRESSED:
// console.log('isMaleFilterOn:', action.isMaleFilterOn)
return { ...state, isMaleFilterOn: action.isMaleFilterOn };
case FEMALE_FILTER_PRESSED:
// console.log('isFemaleFilterOn:', action.isFemaleFilterOn)
return { ...state, isFemaleFilterOn: action.isFemaleFilterOn };
In my React Native Container Component, I have attempted some (suspect) ES6 destructuring in mapStateToProps which, if I don't include, the entire filterBarState returns undefined
const mapStateToProps = ({ LB }) => {
const { filterBarState: { isMaleFilterOn, isFemaleFilterOn, currentSelectedEvent, currentSelectedRow }, listItems, isCurrentlySelected } = LB;
return { isMaleFilterOn, isFemaleFilterOn, currentSelectedEvent, currentSelectedRow, listItems, isCurrentlySelected };
Any tips / suggestions on a fix would be greatly appreciated!
Based on the EVENT_FILTER_PRESSED handler, it looks like you are not updating the isMaleFilterOn and isFemaleFilterOn at the correct level. Try this:
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case EVENT_FILTER_PRESSED:
return {
// Reducer composition
filterBarState: eventFilter(state.filterBarState, action),
listItems: eventItems(state.listItems, action)
};
case MALE_FILTER_PRESSED:
// console.log('isMaleFilterOn:', action.isMaleFilterOn)
return { ...state, filterBarState: { ...state.filterBarState, isMaleFilterOn: action.isMaleFilterOn } };
case FEMALE_FILTER_PRESSED:
// console.log('isFemaleFilterOn:', action.isFemaleFilterOn)
return { ...state, filterBarState: { ...state.filterBarState, isFemaleFilterOn: action.isFemaleFilterOn } };
}