I am a newbie in react native. I am implementing redux saga in my app. but the saga request for fetch method is not called on 'Random photos list' text click.
Here is my code:
App.js
// Imports: Dependencies
import React from 'react';
import { Provider } from 'react-redux';
// Imports: Screens
import Counter from './Counter';
// Imports: Redux Store
import { store } from '../Stores/store';
// React Native App
export default function App() {
return (
// Redux: Global Store
<Provider store={store}>
<Counter />
</Provider>
);
}
Counter.js
render() {
debugger;
return (
<View style={styles.headerStyle}>
<TouchableHighlight onPress={this.props.fetchData}>
<Text style={styles.headline}>Random Photos List</Text>
</TouchableHighlight>
<FlatList
data={this.props.photos}
renderItem={({item}) =>
<TouchableHighlight onPress={ () => this.showAlert() }>
<View style={styles.container}>
<View style={styles.buttonContainer1}>
<Text style={styles.textStyle1}>{item.id}</Text>
</View>
<View style={styles.buttonContainer2}>
<Text style={styles.textStyle2}>{item.title}</Text>
</View>
</View>
</TouchableHighlight>
}
keyExtractor={item => item.id}
/>
</View>
)
}
const mapStateToProps = (state) => {
debugger;
console.log('State:');
console.log(state);
// Redux Store --> Component
return {
photos: state.photos.photos
};
};
// Map Dispatch To Props (Dispatch Actions To Reducers. Reducers Then Modify The Data And Assign It To Your Props)
const mapDispatchToProps = dispatch => {
return {
// dispatching plain actions
fetchData: () => dispatch({ type: 'FETCH_PHOTO_REQUESTED' })
}
}
// Exports
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
Reducer/index.js
// Imports: Dependencies
import { combineReducers } from 'redux';
// Imports: Reducers
import counterReducer from './counterReducer';
// Redux: Root Reducer
const rootReducer = combineReducers({
photos: counterReducer,
});
// Exports
export default rootReducer;
CounterReducer.js
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case 'FETCH_PHOTO_SUCCESS':
return {
...state,
photos: action.payload
}
default:
return state;
}
};
// Exports
export default counterReducer;
store.js
// Imports: Dependencies
import { createStore, applyMiddleware } from 'redux';
import { createLogger } from 'redux-logger';
import createSagaMiddleware from 'redux-saga';
// Imports: Redux Root Reducer
import rootReducer from '../Reducers/index';
// Imports: Redux Root Saga
import { rootSaga } from '../Sagas/index';
// Middleware: Redux Saga
const sagaMiddleware = createSagaMiddleware();
// Redux: Store
const store = createStore(
rootReducer,
applyMiddleware(
sagaMiddleware,
createLogger(),
),
);
// Middleware: Redux Saga
sagaMiddleware.run(rootSaga);
// Exports
export {
store,
}
Sagas/index.js
// Imports: Dependencies
import { all, fork} from 'redux-saga/effects';
// Imports: Redux Sagas
import {fetchPhotos} from './counterSaga';
// Redux Saga: Root Saga
export function* rootSaga() {
yield fork(fetchPhotos);
}
and
counterSaga.js
import { delay, takeEvery, takeLatest, put } from 'redux-saga/effects';
function* fetchPhotosAsync() {
try {
const payload = yield call(getData);
debugger;
yield put({ type: 'FETCH_PHOTO_SUCCESS', payload });
} catch (e) {
debugger;
yield put({ type: 'FETCH_PHOTO_ERROR', payload: e });
}
}
function getData() {
debugger;
return fetch("https://jsonplaceholder.typicode.com/photos").then(response =>
response.json()
);
}
// Watcher: Increase Counter Async
export function* fetchPhotos() {
// Take Last Action Only
debugger;
yield takeLatest('FETCH_PHOTO_REQUESTED', fetchPhotosAsync);
};
I have been debugging for 2 days now. still not able to find the cause. Please Help.
Any Help is appreciated. Thank you.
Related
I just updated my next-redux-wrapper package and did some changes according to their latest doc. However, the component didn't receive the props returned from MyComponent.getInitialProps = wrapper.getInitialPageProps(store => (context) => ({ foo: "bar }))
When I console the props on MyComponent, there is no "foo"
Has anyone solved this or know why this happens?
I tried to change my __app.js and use getInitialProps without wrapper.getInitialPageProps, but it changes nothing. Here is my __app.js
import { wrapper } from 'store';
import { Provider } from 'react-redux';
import App from 'next/app';
const MyApp = ({ Component, ...rest }) => {
const { store, props } = wrapper.useWrappedStore(rest);
return (
<Provider store={store}>
<Component {...props.pageProps} />
</Provider>
);
};
MyApp.getInitialProps = wrapper.getInitialAppProps(
(store) => async (appCtx) => {
const appProps = await App.getInitialProps(appCtx);
return {
pageProps: {
...appProps.pageProps,
},
};
}
);
export default MyApp;
I am trying to get redux working in my react-native app. Basically, I have a signIn action defined in my authActions.js file:
const signInAction = () => {
return {
type: 'signIn',
};
};
export { signInAction };
Then I have an authReducer defined as this in authReducer.js:
const initialState = {
isAuthenticated: false,
}
const authReducer = (state = initialState, action) => {
switch(action.type) {
case "signIn":
return Object.assign({}, state, {
isAuthenticated: true,
})
default: return state;
}
};
export default authReducer;
I combine that reducer in my rootReducer.js file
import { combineReducers } from 'redux';
import auth from 'app/src/redux/reducers/authReducer.js';
const rootReducer = combineReducers({
auth,
});
export default rootReducer;
and then created a store in reduxIndex.js:
import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import rootReducer from 'app/src/redux/reducers/rootReducer.js';
let store = createStore(rootReducer, applyMiddleware(thunkMiddleware));
export default store;
I wrapped my app in a <Provider> component, and that seems to be working fine (I can read from the state and see the value of isAuthenticated. However, when I try to dispatch an action using mapDispatchToProps in one of my views the function is undefined:
// More imports
// ...
import { connect } from 'react-redux';
import { signInAction } from 'app/src/redux/actions/authActions.js';
const mapStateToProps = (state) => {
return {};
}
const mapDispatchToProps = (dispatch) => {
return {
onSignIn: () => { dispatch(signInAction) },
};
}
class SignIn extends Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: "",
}
}
onSignInPress() {
// ******* this is where the error occurrs ****
this.props.onSignIn();
}
render() {
const {navigation} = this.props;
return (
<View style={SignInStyles.container}>
<ScrollView>
<View>
<Button
large
title="SIGN IN"
backgroundColor={colors.primary}
onPress={this.onSignInPress}
/>
</View>
</ScrollView>
</View>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(SignIn);
I cant really see where I am going wrong, but im sure its a simple mistake somewhere. The specific error I get is :
"undefined is not an object. Evaluating this.props.onSignIn"
The onSignInPress callback isn't bound to any particular object, so when it gets called this is undefined.
The easy way to fix it is to use arrow syntax to make it always be bound. In your class definition:
onSignInPress = () => {
this.props.onSignIn();
}
Google found me this Medium article from Miron Machnicki which explains the differences and possible alternative syntaxes in pretty good detail.
No matter what I do, I can't get rid of the mistake. I have often rewritten the actions but the error remains. I also wrote thunk at the top of the createstore. It would be great if you could support me a little bit.
My action, nothing special here only a fetch call to get my players
import fetch from "cross-fetch"
export const SET_PLAYERS = "setplayers"
export const setPlayers = players => {
return{
type: "setplayers",
players
}
}
export const fetchPlayers = () => (dispatch, getState) => {
return fetch("http://localhost:4444/api/players")
.then(response => response.json())
.then(players => {
dispatch(setPlayers(players))
}).catch(err => {
console.log("Could not fetch assortments" , err)
})
}
Component, at this point in time only a dummy to invoke the action:
import React from "react"
import PropTypes from "prop-types"
import { fetchPlayers } from "./action"
import { connect } from "react-redux"
import EnhancedTable from "../components/list/List"
import getPlayers from "./reducer"
class PlayerTable extends React.Component {
constructor(props) {
super(props)
this.state = {
}
}
componentDidMount(){
this.props.fetchPlayers()
}
render() {
console.log("#######", this.props.players)
return (
<EnhancedTable />
)
}
}
PlayerTable.propTypes = {
classes: PropTypes.object.isRequired,
}
const mapStateToProps = state => ({
players: getPlayers(state)
})
export default connect(mapStateToProps, { fetchPlayers })(PlayerTable)
Reducer
import { SET_PLAYERS } from "./action"
const setPlayers = (state={}, action) => {
console.log("ACTION", action)
switch (action.type) {
case SET_PLAYERS:
return {...state, players: action.players}
default:
return state
}
}
export default setPlayers
export const getPlayers = state => ([])
CombinedReducers
import { combineReducers } from "redux"
import { reducer as formReducer } from "redux-form"
import showProgressbar from "../components/progressbar/reducer"
import showSnackBar from "../components/snackbar/reducer"
import setPlayers from "../player/reducer"
export default combineReducers({
form: formReducer,
showProgressbar,
showSnackBar,
setPlayers
})
CreateStore
import App from "./App"
import React from "react"
import rootReducer from "./reducers"
import thunk from "redux-thunk"
import { render } from "react-dom"
import { createStore, applyMiddleware, compose } from "redux"
import { Provider } from "react-redux"
import { createLogger } from "redux-logger"
const store = createStore(
rootReducer,
compose(applyMiddleware(thunk),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
))
render(
<Provider store={store}>
<App />
</Provider>,
/* eslint-disable*/
document.getElementById("root")
/* eslint-enable */
)
You've defined mapStateToProps properly, but don't you need to do the same with mapDispatchToProps for the second argument to connect()?
const mapStateToProps = state => ({
players: getPlayers(state)
})
const mapDispatchToProps = dispatch => ({
fetchPlayers() {
dispatch(fetchPlayers())
}
})
export default connect(mapStateToProps, mapDispatchToProps)(PlayerTable)
Goal
To click the next button and dispatch two actions to the redux store that:
Firstly, update the skipAmount value.
And then use the updated skipAmount value to generate apiQuery (a string that is being used to make a request to a server).
Problem
The skipAmount value is not being updated between action 1 & 2
Example
I have created a CodeSandbox that clear demonstrates the issue that I am having. Notice that the skipAmount value is 100 (or one click event) ahead of apiQuery.
https://codesandbox.io/s/o2vvpwqo9
Code
Index.js
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore } from "redux";
import App from "./App";
import reducer from "./reducer";
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
App.js
import React from 'react';
import { connect } from 'react-redux';
const mapStateToProps = state => ({
...state,
});
const queryGenerator = props => `www.apiExample.com?skipAmount=${props.skipAmount}`;
const ConnectedApp = props => (
<div className="App">
<button
onClick={() => {
props.dispatch({ type: 'SET_SKIP_AMOUNT_PLUS_100' });
props.dispatch({ type: 'SET_API_QUERY', payload: queryGenerator(props) });
}
}
>
Next
</button>
<p>Skip amount on redux: {props.skipAmount}</p>
<p>Query being generated: {props.apiQuery}</p>
</div>
);
export default connect(mapStateToProps)(ConnectedApp);
reducer.js
const reducerDefaultState = {
skipAmount: 0,
apiQuery: 'www.apiExample.com',
};
export default (state = reducerDefaultState, action) => {
switch (action.type) {
case 'SET_SKIP_AMOUNT_PLUS_100':
return {
...state,
skipAmount: state.skipAmount + 100,
};
case 'SET_API_QUERY':
return {
...state,
apiQuery: action.payload,
};
default:
return state;
}
};
In App.js queryGenerator(props) you are passing the unchanged props from the onClick.
props are'nt changing from SET_SKIP_AMOUNT_PLUS_100 until rerender.
onClick={() => {
props.dispatch({ type: 'SET_SKIP_AMOUNT_PLUS_100' });
props.dispatch({ type: 'SET_API_QUERY', payload: queryGenerator(props) });
}
In 'SET_SKIP_AMOUNT_PLUS_100' you are changing the redux state. (not the current props in component),
and in 'SET_API_QUERY' your are using the components props (not what's in redux) because props has'nt updated yet.
I'm new to react and reactNative.
What is "dispatch is not a function. dispatch is an instance of Object."?
mapStateToProps works well.
However, mapDispatchToProps don't work.
I need to handle the nested action.
My Question is that
1. How Can I solve this problem(I want to just dispatch.)?
My code is below.
import React, { Component } from 'react'
import { View, Text } from 'react-native'
import { connect } from 'react-redux'
class User extends Component<Props> {
render() {
return (
<View>
<Text>{this.props.name}</Text>
<Text onPress={this.props.onKabaya}>kabaya?</Text>
</View>
);
}
}
const mapStateToProps = state => ({
name: state.User.user.name
})
const mapDispatchToProps = dispatch = ({
onKabaya: state => dispatch({ type: 'ADD_XXX' })
})
export default connect(mapStateToProps, mapDispatchToProps)(User);
//reducer
const INITIAL_STATE = { //nested action?
user: {
name: 'JOE'
},
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case 'ADD_XXX':
return {
user: {
name: 'XXX'
}
};
default:
return state;
}
}
Is there js ninja?
thanks.