Unable to fetch data from api using fetch() - javascript

I have a react-native project implemented with redux where I am trying to fetch data from an api using fetch.I am unable to fetch the data from the api.Also,it doesn't give any errors. My code is as shown below:
Action.js
//import axios from 'axios';
export const FETCH_DATA = 'fetch_data';
export const FETCH_SUCCESS = 'fetch_success';
export function fetchData() {
return dispatch => {
return(fetch('https://api.myjson.com/bins/fz62x'))
.then(res => res.json())
.then(data => {
dispatch({
type: FETCH_DATA,
payload: data
})
}
)
}
}
I have 2 reducer files:
fetch_data.js
import FETCH_DATA from '../actions'
const initialState = {
result:[],
isFetching: false,
error: false
}
export default function fetchReducer(state = initialState, action) {
switch (action.type) {
case FETCH_DATA: {
return {
...state,
isFetching: true,
result: action.payload.data
}
}
default:
return state
}
}
index.js
import { combineReducers } from 'redux';
import fetchData from './fetch_data';
const rootReducer = combineReducers({
result: fetchData
})
export default rootReducer;
My component where I am trying to access the data fetched from the api:
HomeScreen.js
import React from 'react';
import { StyleSheet,
Text,
View,
ActivityIndicator
} from 'react-native';
import { bindActionCreators } from 'redux';
import reducer from '../reducers/fetch_data';
import thunk from 'redux-thunk';
import { connect } from 'react-redux';
import { fetchData } from '../actions';
class HomeScreen extends React.Component {
static navigationOptions = {
header: null
}
componentDidMount() {
this.props.fetchData()
}
render() {
const { result, isFetching } = this.props.result;
if (isFetching) {
return(
<View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
<ActivityIndicator size={'large'} />
</View>
)
} else {
return(
<View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
<Text>{result.length}</Text>
</View>
)
}
}
}
function mapStateToProps(state) {
return {
result: state.result
}
}
function mapDispatchToProps(dispatch) {
return {
...bindActionCreators({ fetchData }, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen);
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'blue'
},
welcome: {
color: '#FFF',
fontSize: 30
}
})
So,in my Homescreen.js where I try to ge the result of the api in <Text>{result}</Text> ,I get a blank page. If I try to get the length of the result props,I get 0.What is the issue with this code,can anyone please help me with this?
NOTE: Also, isFetching props is returning the default value,i.e. false, so I am directly navigated to the other page where result prop is mentioned.
EDIT 1 Updated files for the action,reducer and component are given below:
Actions.js
//import axios from 'axios';
//import { FETCH_DATA, FETCH_DATA_SUCCESS, FETCH_DATA_FAILURE } from '/constants';
export const FETCH_DATA = 'FETCH_DATA';
export const FETCH_DATA_SUCCESS = 'FETCH_DATA_SUCCESS';
export const FETCH_DATA_FAILURE = 'FETCH_DATA_FAILURE';
export function fetchData() {
return (dispatch) => {
dispatch(getData())
fetch('https://api.myjson.com/bins/fz62x')
.then(res => res.json())
.then(json => dispatch(getDataSuccess(json.results)))
.catch(err => dispatch(getDataFailure(err)))
}
}
function getData() {
return {
type: FETCH_DATA
}
}
function getDataSuccess(data) {
return {
type: FETCH_DATA_SUCCESS,
data
}
}
function getDataFailure() {
return {
type: FETCH_DATA_FAILURE,
}
}
fetch_data.js
import FETCH_DATA from '../actions';
import FETCH_DATA_SUCCESS from '../actions';
import FETCH_DATA_FAILURE from '../actions';
const initialState = {
result_array:[],
isFetching: false,
error: false
}
export default function fetchReducer(state = initialState, action) {
switch (action.type) {
case FETCH_DATA: {
return {
...state,
isFetching: true,
}
}
case FETCH_DATA_SUCCESS: {
return {
...state,
isFetching: false,
result_array: action.payload
}
}
case FETCH_DATA_FAILURE:
return {
...state,
isFetching: false,
error:true
}
default:
return state
}
}
HomeScreen.js
import React from 'react';
import { StyleSheet,
Text,
View,
ActivityIndicator
} from 'react-native';
import { bindActionCreators } from 'redux';
import reducer from '../reducers/fetch_data';
import thunk from 'redux-thunk';
import { connect } from 'react-redux';
import { fetchData } from '../actions';
class HomeScreen extends React.Component {
static navigationOptions = {
header: null
}
componentDidMount() {
this.props.fetchData()
}
render() {
const { result, isFetching } = this.props.result;
if (isFetching) {
return(
<View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
<ActivityIndicator size={'large'} />
</View>
)
} else {
return(
<View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
<Text>{result}</Text>
</View>
)
}
}
}
function mapStateToProps(state) {
return {
result_array: state.result.result_array
}
}
function mapDispatchToProps(dispatch) {
return {
...bindActionCreators({ fetchData }, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen);
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'blue'
},
welcome: {
color: '#FFF',
fontSize: 30
}
})

There are a few things you need to fix. It would be better if you upload the codes to github or codesandbox then we can understand you code structure easier.
First of all, return (fetch('url')).then or return fetch(url).then, both of them work as you expect, but you should keep in mind that the redux-thunk doesn't care about you return value, this promise has nothing to do, that's alright, it doesn't need to do anything.
Let's fix your syntax error in fetch_data.js first:
import FETCH_DATA from '../actions'
should be :
import { FETCH_DATA } from '../actions' // I don't know why didn't your build tool report an error here.
According to your purpose, I think you should import the FETCH_SUCCESS here as well.
Then we can talk about your action and reducer flow :
return(fetch('https://api.myjson.com/bins/fz62x'))
.then(res => res.json())
.then(data => {
dispatch({
type: FETCH_DATA,
payload: data
})
}
)
}
and reducer :
switch (action.type) {
case FETCH_DATA: {
return {
...state,
isFetching: true,
result: action.payload.data
}
}
default:
return state
}
You only deal with FETCH_DATA(and I think you probably should use FETCH_SUCCESS here), another action type should be dispatch and parse as well.
I will suggest the flow like this :
Action.js:
export const FETCH_DATA = "fetch_data";
export const FETCH_SUCCESS = "fetch_success";
export function fetchData() {
return dispatch => {
fetch("https://api.myjson.com/bins/fz62x")
.then(res => res.json())
.then(data => {
dispatch({
type: FETCH_SUCCESS,
payload: data
});
});
dispatch({
type: FETCH_DATA
});
};
}
With this you now dispatch FETCH_DATA to tell the application you start to fetch data first, and dispatch FETCH_SUCCESS when fetch succeed.
And the fetch_data.js:
import { FETCH_DATA, FETCH_SUCCESS } from "./actions";
const initialState = {
result: [],
isFetching: false,
error: false
};
export default function fetchReducer(state = initialState, action) {
switch (action.type) {
case FETCH_DATA: {
return {
...state,
isFetching: true,
error: false
};
}
case FETCH_SUCCESS: {
return {
result: action.payload, // The action.payload.data isn't what you want
isFetching: false,
error: false
};
}
default:
return state;
}
}
And now your reducer will respond correctly with FETCH_DATA and FETCH_SUCCESS
And another thing is I don't know why you import thunk and reducer in your
Homescreen.js, it should not be there if you are not going to create you redux store there (I assume that you have a <Provider store={store}>{...your application}</Provider> upon the Homescreen which you should have)

I'm not sure about your problem but hope this help.
First, Your Action.js, you dispatch payload with array:
dispatch({
type: FETCH_DATA,
payload: data
})
that data is array
[
{ createdOn: '', taskList: [{}, {}, ...] },
{ createdOn: '', taskList: [{}, {}, ...] },
...
]
In your fetch_data.js You received payload with array but access .data it will got undefined, you have to change to result: action.payload
return {
...state,
isFetching: true,
result: action.payload.data // <-- undefined
}
but I think you should have type FETCH_DATA to return { isFetching: true } and FETCH_SUCCESS return { isFetching: false, result: action.payload like this
// action.js
fetchData() {
dispatch({
type: FETCH_DATA
})
return fetch('https://api.myjson.com/bins/fz62x')
.then(res => res.json())
.then(data => {
dispatch({
type: FETCH_SUCCESS,
payload: data
})
})
}
// fetch_data.js
switch (action.type) {
case FETCH_DATA: {
return {
...state,
isFetching: true
}
}
case FETCH_SUCCESS: {
return {
...state,
isFetching: false,
result: action.payload
}
}
}
but It looks a bit weird because you got 0 when use get the length of result, it should be undefined unless it return defaultValue of state that result is empty array

You must have 50 reputation to comment
Sorry, but i just seen that your edit 1 has something wrong. iam i right
case FETCH_DATA_SUCCESS: {
return {
...state,
isFetching: false,
result_array: action.payload <-- this is undefined. it should be action.data from your action
}
}

Related

Dispatch for useContext not being called in useEffect

I am trying to build an app based on https://github.com/orbitdb/orbit-db-control-center/ which works as intended but when I ported it to my application there are some issues.
Within a useEffect I am calling dispatch which is not changing the application's state. The dispatches are within async functions which are being called and behave as intended but the dispatches aren't updating the UI. I am using parcel to help hot-reload during dev. On page load the dispatches aren't being called but when the page is updated (not-refreshed) using parcel hot-reload the dispatches work as intended.
Systems.js
const [appState, dispatch] = useStateValue()
React.useEffect(() => {
dispatch({ type: actions.PROGRAMS.SET_PROGRAMS_LOADING, loading: true })
initIPFS().then(async (ipfs) => {
dispatch({ type: actions.SYSTEMS.SET_IPFS, ipfsStatus: 'Started' })
initOrbitDB(ipfs).then(async () => {
dispatch({ type: actions.SYSTEMS.SET_ORBITDB, orbitdbStatus: 'Started' })
const programs = await getAllDatabases(pid)
dispatch({ type: actions.PROGRAMS.SET_PROGRAMS, programs: programs.reverse() })
dispatch({ type: actions.PROGRAMS.SET_PROGRAMS_LOADING, loading: false })
})
})
}, [dispatch])
App.js
import React from 'react'
import {Outlet} from 'react-router-dom'
import { actions, loadingState,
StateProvider
} from './state'
import {Systems} from './components/Systems'
import {Header} from './components/Header'
import './index.css'
export function DBView () {
const initialState = {
user: null,
loginDialogOpen: false,
createDBDialogOpen: false,
addDBDialogOpen: false,
programs: [],
program: false,
db: null,
entries: [],
orbitdbStatus: 'Starting',
ipfsStatus: 'Starting',
loading: {
programs: false
}
}
const reducer = (state, action) => {
console.log(action)
switch (action.type) {
case actions.SYSTEMS.SET_ORBITDB:
return {
...state,
orbitdbStatus: action.orbitdbStatus
}
case actions.SYSTEMS.SET_IPFS:
return {
...state,
ipfsStatus: action.ipfsStatus
}
case actions.PROGRAMS.SET_PROGRAM:
return {
...state,
program: action.program
}
case actions.PROGRAMS.SET_PROGRAM_LOADING:
return {
...state,
program: loadingState
}
case actions.PROGRAMS.SET_PROGRAMS:
return {
...state,
programs: action.programs
}
case actions.DB.SET_DB:
return {
...state,
db: action.db,
entries: action.entries,
}
case actions.DB.OPEN_CREATEDB_DIALOG:
return {
...state,
createDBDialogOpen: true
}
case actions.DB.CLOSE_CREATEDB_DIALOG:
return {
...state,
createDBDialogOpen: false
}
case actions.DB.OPEN_ADDDB_DIALOG:
return {
...state,
addDBDialogOpen: true
}
case actions.DB.CLOSE_ADDDB_DIALOG:
return {
...state,
addDBDialogOpen: false
}
case actions.PROGRAMS.SET_PROGRAMS_LOADING:
return {
...state,
loading: { ...state.loading, programs: action.loading }
}
default:
return state
}
}
return (
<StateProvider initialState={initialState} reducer={reducer}>
<Header />
<Systems />
<Outlet />
</StateProvider>
)
}
state/index.js
import React, { createContext, useReducer, useContext } from 'react'
export const StateContext = createContext()
export const StateProvider = ({ reducer, initialState, children }) => (
<StateContext.Provider value={useReducer(reducer, initialState)}>
{children}
</StateContext.Provider>
)
export const useStateValue = () => useContext(StateContext)
export const actions = {
DB: {
OPEN_CREATEDB_DIALOG: 'OPEN_CREATEDB_DIALOG',
CLOSE_CREATEDB_DIALOG: 'CLOSE_CREATEDB_DIALOG',
OPEN_ADDDB_DIALOG: 'OPEN_ADDDB_DIALOG',
CLOSE_ADDDB_DIALOG: 'CLOSE_ADDDB_DIALOG',
SET_DB: 'SET_DB'
},
SYSTEMS: {
SET_IPFS: 'SET_IPFS',
SET_ORBITDB: 'SET_ORBITDB'
},
PROGRAMS: {
SET_PROGRAMS: 'SET_PROGRAMS',
SET_PROGRAMS_LOADING: 'SET_PROGRAMS_LOADING',
SET_PROGRAM: 'SET_PROGRAM',
SET_PROGRAM_LOADING: 'SET_PROGRAM_LOADING'
}
}
export const loadingState = 'loading'

useSelector doesn't update value in Next.js

I have a problem, createAsyncThunk function makes request to server (axios) and then get data, after that extraReducers handle builder.addCase in it and makes state.value = action.payload, then console.log(state.value) writes value from server. Great! It works, but when I use useSelector it sees existing value from initialState but get value only when it was first time initialized (null or just []) not updated after dispatch in wrapper.getServerSIdeProps. Same with just reducers and function in it. It works change state (console.log write it) but useSelector doesn't give me updated value.
UPDATE:
If you have same issue.
Just give up, don't use next-redux-wrapper. Context Api.
Slice code
import { createAsyncThunk, createSlice, PayloadAction } from '#reduxjs/toolkit';
import axios from 'axios';
import { HYDRATE } from 'next-redux-wrapper';
// types
import { IInitialStateV1 } from '../types/store';
import { ITrack } from '../types/tracks/track';
export const fetchData = createAsyncThunk('main/fetchData', async (): Promise<ITrack[]> => {
const { data } = await axios.get<ITrack[]>('http://localhost:5000/track');
return data;
})
const initialState: IInitialStateV1 = {
pause: true,
currentTime: 0,
volume: 0,
duration: 0,
active: null,
tracks: [],
}
export const mainSlice = createSlice({
name: 'main',
initialState,
reducers: {
setPause(state, action: PayloadAction<boolean>) {
state.pause = action.payload;
},
setTime(state, action: PayloadAction<number>) {
state.currentTime = action.payload;
},
setVolume(state, action: PayloadAction<number>) {
state.volume = action.payload;
},
setDuration(state, action: PayloadAction<number>) {
state.duration = action.payload;
},
setActive(state, action: PayloadAction<ITrack>) {
state.active = action.payload;
state.currentTime = 0;
state.duration = 0;
}
},
extraReducers: (builder) => {
// [HYDRATE]: (state, action) => {
// return {
// ...state,
// ...action.payload,
// }
// },
// [fetchData.fulfilled.toString()]: (state, action: PayloadAction<ITrack[]>) => {
// state.tracks = action.payload;
// }
builder.addCase(HYDRATE, (state, action: any) => {
return {
...state,
...action.payload,
}
}).addCase(fetchData.fulfilled, (state, action: PayloadAction<ITrack[]>) => {
// return {
// ...state,
// ...action.payload,
// }
state.tracks = action.payload;
});
}
})
export const { setPause, setTime, setVolume, setDuration, setActive } = mainSlice.actions;
export default mainSlice.reducer;
configurate store
import { AnyAction, configureStore, ThunkDispatch } from '#reduxjs/toolkit';
import { createWrapper, MakeStore, Context } from 'next-redux-wrapper';
import mainRed from './index';
const makeStore = () => configureStore({
reducer: {
main: mainRed
},
})
type AppStore = ReturnType<typeof makeStore>;
export type RootState = ReturnType<AppStore['getState']>;
export type AppDispatch = AppStore['dispatch'];
export type NextThunkDispatch = ThunkDispatch<RootState, void, AnyAction>;
export const wrapper = createWrapper<AppStore>(makeStore);
hooks for TypeScript
import { useDispatch, useSelector, TypedUseSelectorHook } from "react-redux";
import { RootState, AppDispatch } from "../store/reducer";
export const useTypeSelector: TypedUseSelectorHook<RootState> = useSelector;
export const useTypeDispath = ()=> useDispatch<AppDispatch>();
getServerSideProps and useSelector (in page)
import { Container, ListItem, Stack, Box, Button } from "#mui/material";
import TrackList from "../../components/TrackList";
// interfaces
import { ITrack } from "../../types/tracks/track";
// import hooks
import { useRouter } from "next/router";
import { useTypeSelector } from "../../hooks/useTypeSelector";
// wrapper
import { NextThunkDispatch, wrapper } from "../../store/reducer";
import { fetchData, setVolume } from "../../store";
export default function Index(): JSX.Element {
const router = useRouter();
const tracks: ITrack[] = useTypeSelector(state => state.main.tracks);
return (
<div className="main">
<Container >
<Stack marginTop={20} sx={{ backgroundColor: "#C4C4C4", fontSize: '24px', fontWeight: 'bold' }}>
<Box p={5} justifyContent="space-between">
<ListItem>List of Tracks</ListItem>
<Button variant="outlined" sx={{ backgroundColor: 'blue', color: 'white' }} onClick={() => router.push('/tracks/create')} >Upload</Button>
</Box>
<TrackList tracks={tracks} />
</Stack>
</Container>
</div>
)
}
export const getServerSideProps = wrapper.getServerSideProps((store) => async () => {
const dispatch = store.dispatch as NextThunkDispatch;
// dispatch(fetchData());
dispatch(setVolume(2));
return {
props: {}
}
})

Unable to Render a FlatList

I'm trying to render a FlatList but I don't see it on the Screen
I get my Data of my Reducer through a Console Log and in the Console I get the correct Data:
User {
"apellido": "Alas",
"correo": "prueba#uno.com",
"id": 2021-02-08T23:52:58.855Z,
"nombre": "Rene",
"telefono": "72457183",
}
Here is my Code:
import React from "react";
import { View, Text, FlatList, StyleSheet } from "react-native";
import { useSelector } from 'react-redux';
import UserItem from "../components/UserItem";
export default function Page2() {
const users = useSelector(state => state.registro.availableUsers);
console.log(users);
if (users.length === 0) {
return <View style={styles.centered} >
<Text>No Existen Usuarios</Text>
</View>
}
return (
<FlatList
data={users}
keyExtractor={item => item.id.toString()}
renderItem={
itemData => <UserItem
nombre={itemData.item.nombre}
apellido={itemData.item.apellido}
telefono={itemData.item.telefono}
coreo={itemData.item.coreo}
onSelect={() => { }}
/>
}
/>
)
};
const styles = StyleSheet.create({
container: {
backgroundColor: '#f9fafd',
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
}
});
As you can see the Console Log shows there is data being Received from the Reducer, but there is no data displayed through the FlatList
As you can see in the Picture
I tried to get to the same Result (Render a List) with the MAP function but still getting an Error:
TypeError: undefined is not a function (near '...users.map...')
Although I know there shouldn't be an Undefined as there is that printed to the Console
Any Ideas?
PS. I think the Issue might be with the Action or Reducer:
Action
//Import Model
import { createStore } from 'redux';
import User from '../../models/user';
//Constant Creation
export const REGISTER = 'REGISTER';
export const createUser = (nombre, apellido, telefono, correo) => {
return async (dispatch) => {
console.log('entra a fun');
try{
console.log('antes de crear');
const createdUser = new User(new Date(), nombre, apellido, telefono, correo);
console.log('despues de crear');
console.log(createUser);
dispatch({type: REGISTER, user: createdUser});
}
catch (err) {
throw err;
}
}
};
Reducer
import { REGISTER } from '../actions/registro';
const initialState = {
availableUsers: [],
}
export default (state = initialState, action) => {
switch (action.type) {
case REGISTER:
return {
...state,
availableUsers: action.user,
};
}
return state;
};
Your available users is just getting one user, instead of updating/appending the new one.
export default (state = initialState, action) => {
switch (action.type) {
case REGISTER:
return {
...state,
availableUsers: [...state.availableUsers, action.user],
};
}
return state;
};
By spreading (...) state.availableUsers, you can append the new user to the end of the existing array.

React Native - Navigating by ID from api with Redux not working

So, i'am using redux for my application and so far it's good. But recently I just hit a wall that stops me from coding for a while. I'am trying to make a navigation using the ID of every item in my database with redux. let's say I have a "category of food" page that is filled with item from my database and each of those items has their own ID, using those ID I'am trying to navigate to a second page which is the "dishes page". If a user clicks a category, the application should display the dishes that the category contains.
As of now, I manage to display the category but I don't know how to apply the navigation.
Whenever I try to add a kind of navigation that I know I'am facing an error:
Error
state_error ( ** UPDATE ** )
You can see all the details in my code.
Here is my code:
App.js ( ** EDIT ** )
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,
View
} from 'react-native';
import { StackNavigator } from 'react-navigation';
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import Reducer from './app/redux/reducers/Reducer';
import AppContainer from './app/container/AppContainer';
import DishContainer from './app/container/DishContainer';
import Dishes from './app/component/Dishes';
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const store = createStoreWithMiddleware(Reducer);
export default class App extends Component{
render() {
return (
<Provider store = { store }>
<Root />
</Provider>
);
}
}
const Root = StackNavigator ({
AppContainer : { screen: AppContainer },
DishContainer : { screen: DishContainer },
Dishes : { screen: Dishes },
})
Action.js
import {
FETCHING_CATEGORY_REQUEST,
FETCHING_CATEGORY_SUCCESS,
FETCHING_CATEGORY_FAILURE,
FETCHING_DISHES_REQUEST,
FETCHING_DISHES_SUCCESS,
FETCHING_DISHES_FAILURE,
} from "./types";
import axios from 'axios';
/* ---------------------- CATEGORY ---------------------------- */
export const fetchingCategoryRequest = () => ({
type: FETCHING_CATEGORY_REQUEST
});
export const fetchingCategorySuccess = (json) => ({
type: FETCHING_CATEGORY_SUCCESS,
payload: json,
});
export const fetchingCategoryFailure = (error) => ({
type: FETCHING_CATEGORY_FAILURE,
payload: error
});
export const fetchCategory = () => {
return (dispatch) => {
axios.get('http://192.168.254.100:3308/categories/')
.then(response => {
dispatch({ type: FETCHING_CATEGORY_SUCCESS, payload: response.data })
})
.catch(error => console.log(error.response.data));
}
}
/* ---------------------- DISHES ---------------------------- */
export const fetchingDishesRequest = () => ({
type: FETCHING_DISHES_REQUEST
});
export const fetchingDishesSuccess = (json) => ({
type: FETCHING_DISHES_SUCCESS,
dish: json,
});
export const fetchingDishesFailure = (error) => ({
type: FETCHING_DISHES_FAILURE,
dish: error,
});
export const fetchDish = () => {
return (dispatch) => {
const { params } = this.props.navigation.state;
axios.get('http://192.168.254.100:3308/categories/' + params.id)
.then(response => {
dispatch({ type: FETCHING_DISHES_SUCCESS, dish: response.data })
})
.catch(error => console.log(error.response.data));
}
}
Reducer.js
const initialState = {
isFetching: false,
errorMessage: '',
category: [],
dishes: [],
};
const categoryReducer = (state = initialState, action) => {
switch(action.type) {
case FETCHING_CATEGORY_REQUEST:
return {
...state,
isFetching: true
};
case FETCHING_CATEGORY_FAILURE:
return {
...state,
isFetching: false,
errorMessage: action.payload
};
case FETCHING_CATEGORY_SUCCESS:
return {
...state,
isFetching: false,
category: action.payload
};
/* --------------------- DISHES ------------------------- */
case FETCHING_DISHES_REQUEST:
return {
...state,
isFetching: true
};
case FETCHING_DISHES_SUCCESS:
return {
...state,
isFetching: false,
dishes: action.dish
};
case FETCHING_DISHES_FAILURE:
return {
...state,
isFetching: false,
errorMessage: action.dish
}
default:
return state;
}
}
export default categoryReducer;
CategoryList.js
export default class CategoryList extends Component {
_renderItem = ({ item }) => {
const { cat_name } = item;
return (
<View style={styles.cardContainerStyle}>
<View style={{ paddingRight: 5 }}>
<TouchableOpacity style = { styles.buttonContainer }>
<Text style={styles.cardTextStyle}
onPress = { () => this.props.navigation.navigate('Dishes', { id: item.cat_id })}>
{cat_name}
</Text>
</TouchableOpacity>
</View>
</View>
);
};
render() {
return (
<FlatList
style={{ flex: 1 }}
data = {this.props.category}
keyExtractor={(item, index) => index.toString()}
renderItem={this._renderItem}
/>
)
}
}
AppContainer.js
import CategoryList from "../component/CategoryList";
import { fetchCategory } from '../redux/actions/Actions';
import { connect } from 'react-redux';
class AppContainer extends Component {
componentDidMount() {
this.props.fetchCategory();
}
render() {
let content = <CategoryList category = { this.props.randomCategory.category }/>;
if (this.props.randomCategory.isFetching) {
content = <ActivityIndicator size="large"/>;
}
return <View style={styles.container}>{content}</View>;
}
}
const mapStateToProps = state => {
return {
randomCategory: state
};
}
export default connect(mapStateToProps, { fetchCategory })(AppContainer);
Dishes.js (This is where I want to navigate from Category)
export default class Dishes extends Component {
_renderItem = ({ item }) => {
const { cat_desc } = item;
return (
<View style={styles.cardContainerStyle}>
<View style={{ paddingRight: 5 }}>
<TouchableOpacity>
<Text style={styles.cardTextStyle}>
{cat_desc}
</Text>
</TouchableOpacity>
</View>
</View>
);
};
render() {
const { params } = this.props.navigation.state;
return (
<FlatList
style={{ flex: 1 }}
data = {this.props.dishes}
keyExtractor={(item, index) => index.toString()}
renderItem={this._renderItem}
/>
)
}
}
DishContainer.js
import Dishes from "../component/Dishes";
import { fetchDish } from '../redux/actions/Actions';
import { connect } from 'react-redux';
class DishContainer extends Component {
componentDidMount() {
this.props.fetchDish();
}
render() {
let content = <Dishes dishes = { this.props.randomDishes.dishes }/>;
if (this.props.randomDishes.isFetching) {
content = <ActivityIndicator size="large"/>;
}
return <View style={styles.container}>{content}</View>;
}
}
const mapStateToProps = state => {
return {
randomDishes: state
};
}
EDIT: Some how the params is not working or the props.navigation.navigate is not calling the item's id from my api. I'am not sure, please help me.
Edit your AppContainer.js like below :
import CategoryList from "../component/CategoryList";
import { fetchCategory } from '../redux/actions/Actions';
import { connect } from 'react-redux';
class AppContainer extends Component {
componentDidMount() {
this.props.fetchCategory();
}
render() {
let content = <CategoryList
navigation = {this.props.navigation}
category = {this.props.randomCategory.category}/>;
if (this.props.randomCategory.isFetching) {
content = <ActivityIndicator size="large"/>;
}
return <View style={styles.container}>{content}</View>;
}
}
const mapStateToProps = state => {
return {
randomCategory: state
};
}
export default connect(mapStateToProps, { fetchCategory })(AppContainer);
The issue is CategoryList can't get navigation props of parent component(AppCountainer), So you have to pass navigation as props.

displaying data from axios using react.js and redux

So I'm learning redux currently and I'm making an app that displays a list of articles. But I can't figured out why my data from my back end isn't showing up. I'm not sure where my error is that preventing my data from my backend from showing up? I know it not the setup of redux because I did simpler app to see if that was the problem and it wasn't so it has to do more with the action, reducers , and component. I would like to go farther eventually when there is more data in the database where it provides a link so it goes to another page that shows all the information about that article.
data from my node backend
[{"_id":"58c71df9f7e4e47f1fe17eeb","article":"words words","author":"Jason","date":"1/2/2014","title":"my article","__v":0}]
fashionActions.js
import axios from "axios";
export function fetchFashionArticle() {
return function(dispatch) {
axios.get("http://localhost:3000/api/fashion")
.then((response) => {
dispatch({type: "FETCH_FASHIONARTICLES_FULFILLED", payload: response.data})
})
.catch((err) => {
dispatch({type: "FETCH_FASHIONARTICLES_REJECTED", payload: err})
})
}
}
export function addFashionArticle(_id, title,date, author, article) {
return {
type: "ADD_FASHIONARTICLE",
payload: {
_id,
title,
date,
author,
article,
},
}
}
export function updateFashionArticle(_id, title,date, author, article) {
return {
type: "UPDATE_FASHIONARTICLE",
payload: {
_id,
title,
date,
author,
article,
},
}
}
export function deleteFashionArticle(id) {
return {type: 'DELETE_FASHIONARTICLE', payload: id}
}
FashionArticle.js
import React from "react";
import { connect } from "react-redux";
import {fetchFashionArticle} from "../actions/fashionActions";
#connect((store) => {
return {
fashionarticles:store.fashionarticles.fashionarticles,
};
})
export default class FashionArticle extends React.component {
fetchFashionArticle() {
this.props.dispatch(fetchFashionArticle())
}
render() {
const { fashionarticles } = this.props;
if(!fashionarticles.length) {
return <button onClick={this.fetchFashionArticles.bind(this)}>Load articles</button>
}
const mappedArticles = fashionarticles.map(fashionarticle => <li>{fashionarticle}</li>)
return(
<div>
<h1>Fashion Article</h1>
<h2>{fashionarticles.title}</h2>
</div>
)
}
}
fashionArticleReducers.js
export default function reducer(state={
fashionarticles: [],
fetching: false,
fetched: false,
error: null,
}, action) {
switch (action.type) {
case "FETCH_FASHIONARTICLES": {
return {...state, fetching: true}
}
case "FETCH_FASHIONARTICLES_REJECTED": {
return {...state, fetching: false, error: action.payload}
}
case "FETCH_FASHIONARTICLES_FULFILLED": {
return {
...state,
fetching: false,
fetched: true,
fashionarticles: action.payload,
}
}
case "ADD_FASHIONARTICLE": {
return {
...state,
fashionarticles: [...state.fashionarticles, action.payload],
}
}
case "UPDATE_FASHIONARTICLE": {
const { _id, title,date,author,article } = action.payload
const newFashionArticles = [...state.fashionarticles]
const fashionarticleToUpdate = newFashionArticles.findIndex(fashionarticle => fashionarticle.id === id)
newFashionArticles[fashionarticleToUpdate] = action.payload;
return {
...state,
fashionarticles: newFashionArticles,
}
}
case "DELETE_FASHIONARTICLE": {
return {
...state,
fashionarticles: state.fashionarticles.filter(fashionarticle => fashionarticle.id !== action.payload),
}
}
}
return state
}
index.js
import { combineReducers } from 'redux';
import user from './testReducers'
import fashionarticles from './fashionArticleReducers';
export default combineReducers({
user,
fashionarticles,
})
You're sending the payload with the axios response as type FETCH_FASHIONARTICLES_DONE but your reducer is listening for FETCH_FASHIONARTICLES_FULFILLED

Categories

Resources