I am developing a mobile app which makes GET calls using fetch api. I am stuck in that I am trying to export json object( fetched from server with fetch method) to another .js file to be used as array, But when I import my function in another.js (below), it returns nothing. I tested my fetch method with console so it works as expected, however I am unable to process data in another.js file. By the way, I have searched a lot and found this post Helpful, but not worked.
Below code is implementation of fetch part and exporting it.(Products.js)
import React, { PureComponent,Component } from "react";
import { connect } from "react-redux";
import { View } from "react-native";
import { productsDataSelector } from "../../Products/ProductsSelectors";
import ProductsList from "../../ProductsList/ProductsList";
import Product from "../../Product/Product";
import { NavigationActions, StackActions } from "react-navigation";
import AnotherComponent from "../../Products/ProductsReducer";
class Products extends PureComponent {
render() {
const { navigation } = this.props;
const { productsData } = this.props;
return (
<View>
<ProductsList list={productsData} isSortable>
{product => <Product product={product} />}
</ProductsList>
</View>
);
}
}
const mapStateToProps = state => ({
productsData: productsDataSelector(state)
});
export const getMoviesFromApiAsync = () =>
fetch('http://localhost:8080/JweSecurityExample/rest/security/retrieveItems')
.then((response) => response.json())
export default connect(
mapStateToProps,
null
) (Products);
Below code is another.js where importing fetch function and processing returning json object without class declaration implemented.
import React, { Component } from "react";
import {getMoviesFromApiAsyncc} from "../screens/Products/Products";
const fakeData = [];
export const someFunc = () => {
fetch('http://localhost:8080/JweSecurityExample/rest/security/retrieveItems')
.then((response) => response.json())
.then((responseJson) => console.log("responsee:"+JSON.stringify(responseJson)))
.then((responseJson) => {fakeData:JSON.stringify(responseJson)})
.catch((error) => {
console.error(error);
});
};
someFunc();
const initialState = {
data:this.fakeData
};
export default (state = initialState,action) => {
return state;
};
Any recommendations ?? Thanx
I don't see where in your code do you call someFunc and one more thing you need to wrap the object that you return from someFunc in braces otherwise it will be treated as the function's body.
export const someFunc = () => {
getMoviesFromApiAsync().then(response => {
fakeData = JSON.stringify(response)
})
};
someFunc();
I suggest that you move getMoviesFromApiAsync to a separate file and call it from your component to get the list of movies.
api.js
export const getMoviesFromApiAsync = () =>
fetch('http://localhost:8080/JweSecurityExample/rest/security/retrieveItems')
.then((response) => response.json());
product.js
import React, { PureComponent,Component } from "react";
import { connect } from "react-redux";
import { View } from "react-native";
import { productsDataSelector } from "../../Products/ProductsSelectors";
import ProductsList from "../../ProductsList/ProductsList";
import Product from "../../Product/Product";
import { NavigationActions, StackActions } from "react-navigation";
import AnotherComponent from "../../Products/ProductsReducer";
// import getMoviesFromApiAsync
import { getMoviesFromApiAsync } from 'PATH_TO_API.JS'
class Products extends Component {
async componentDidMount(){
const list = await getMoviesFromApiAsync();
console.log(list);
}
render() {
const { navigation } = this.props;
const { productsData } = this.props;
return (
<View>
<ProductsList list={productsData} isSortable>
{product => <Product product={product} />}
</ProductsList>
</View>
);
}
}
Related
I'm currently having trouble fetching an API using redux while displaying it a FlatList.
This is my actions code:
import { GET_API } from "../actionTypes";
import * as React from 'react';
const url = "https://data.binance.com/api/v3/ticker/24hr"
export const getAPI = () => {
React.useEffect(() => {
fetch(URL)
.then (x => x.json())
.then(json => {
return {
type: GET_API,
payload: {
title: json
}
}
})
}, [])
}
Here is my reducer code:
import { GET_API } from '../actionTypes/index';
var initialState = {
tasks: [],
};
export default function (state = initialState, action) {
if (action.type == GET_API) {
return {
...state,
tasks: [...state.tasks, { title: action.payload.title }]
}
}
return state;
}
And this is my ApiFetch code:
import { connect } from 'react-redux';
import {
View,
Text,
Button,
TextInput,
FlatList,
ScrollView
} from 'react-native';
import { useState } from 'react';
import { getAPI } from '../redux/actions/index';
const mapStateToProps = (state) => {
return { tasks: state.reducer.tasks };
};
const mapDispatchToProps = { getAPI };
function App({ tasks, get_API }) {
return (
<ScrollView>
<FlatList
data={tasks}
renderItem={({ item }) => (
<View>
<Text>{item.symbol}</Text>
</View>
)}
/>
</ScrollView>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
The way I learned is using a useState so I believe putting it in my actions is wrong but even without the useState it's still not displaying.
React.useEffect is a React hook, so it's only validly called in a React function component or custom React hook. If you are using "legacy redux", i.e. not the newer, better, and current redux-toolkit, then you'll need to ensure you have setup/configured your Redux store to include the Thunk middleware.
See Configuring the Store for how to install and apply the Thunk middleware.
import { createStore, applyMiddleware } from 'redux'
import thunkMiddleware from 'redux-thunk'
import { composeWithDevTools } from 'redux-devtools-extension'
import rootReducer from './reducer'
const composedEnhancer = composeWithDevTools(applyMiddleware(thunkMiddleware))
// The store now has the ability to accept thunk functions in `dispatch`
const store = createStore(rootReducer, composedEnhancer)
export default store
getApi needs to be converted to a thunk, i.e. an asynchronous action. These are typically functions that return a thunk function that is passed both a dispatch and getState function. These are so the thunk can access current state, if necessary, and dispatch further actions to the store.
export const getApi = () => async (dispatch) => {
const response = await fetch(URL);
const title = await response.json();
dispatch({
type: GET_API,
payload: { title },
);
return title;
};
Dispatch the getApi action when the component mounts via a useEffect hook call.
import { useEffect } from 'react';
import { connect } from 'react-redux';
import {
View,
Text,
Button,
TextInput,
FlatList,
ScrollView
} from 'react-native';
import { getApi } from '../redux/actions/index';
function App({ tasks, getApi }) {
useEffect(() => {
getApi();
}, []);
return (
<ScrollView>
<FlatList
data={tasks}
renderItem={({ item }) => (
<View>
<Text>{item.symbol}</Text>
</View>
)}
/>
</ScrollView>
);
}
const mapStateToProps = (state) => ({
tasks: state.reducer.tasks,
});
const mapDispatchToProps = {
getApi,
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
The connect Higher Order Component has fallen a bit out of favor. It's preferable to use the useDispatch and useSelector hooks in modern React-Redux code.
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
View,
Text,
Button,
TextInput,
FlatList,
ScrollView
} from 'react-native';
import { getApi } from '../redux/actions/index';
function App() {
const dispatch = useDispatch();
const tasks = useSelector(state => state.reducer.tasks);
useEffect(() => {
dispatch(getApi());
}, []);
return (
<ScrollView>
<FlatList
data={tasks}
renderItem={({ item }) => (
<View>
<Text>{item.symbol}</Text>
</View>
)}
/>
</ScrollView>
);
}
export default App;
Given all this, it is highly recommended to update and start using redux-toolkit. If you are already familiar with Redux/React-Redux then it'll likely be a 10-15 integration and all the current/existing reducers and actions will continue to work. What this will allow you to do is to write modern React-Redux which is much less boiler-platey, also already has thunk middleware included and active by default so asynchronous actions will work right out of the box, and allows you to write mutable reducer updates.
For example, the above tasks state & reducer function, and getApi action using RTK:
import { createSlice, createAsyncThunk } from '#reduxjs/toolkit';
const initialState = {
tasks: [],
};
export const getApi = createAsyncThunk(
"tasks/getApi",
async (_, { dispatch }) => {
const response = await fetch(URL);
const title = await response.json();
return title;
}
);
const tasksSlice = createSlice({
name: "tasks",
initialState,
extraReducers: builder => {
builder.addCase(getApi.fulfilled, (state, action) => {
const { title } = action.payload;
state.push({ title });
});
};
});
export default tasksSlice.reducer;
I can get the data out correctly and see it in the console as I want it to display but mapping and getting it through is the issue I seem to fail on..
This is my code
import React, {useState, useEffect} from 'react'
import axios from 'axios';
import server from '../backend/server.jsx';
import Home from './Home';
function ListImage() {
const [api, setApi] = useState('');
const getAllData = () => {
axios
.get(`${server}/images`)
.then((response) => {
console.log(response.data);
setApi(response.data);
})
.catch((error) => {
console.log(error);
});
}
useEffect(() => {
getAllData();
},[]);
return (
<>
{api ?
api.map((item) => {
console.log(item);
return <Home data={item.data} />;
}): <p>Not found</p>}
</>
)
}
export default ListImage
And then passing to this where i only get undefined in console
import React from 'react'
function Home({ data }) {
console.log(data)
return (
<>
<p>{data}</p>
</>
)
}
export default Home
Try with this. I think your map function gets called when the initial render. Make sure the response. data should return an array.
ps: You render your home component in an array. That's wrong. Pass the data to the component and map your array on the home component.
import React, {useState, useEffect} from 'react'
import axios from 'axios';
import server from '../backend/server.jsx';
import Home from './Home';
function ListImage() {
const [data, setData] = useState(null);
const getAllData = () => {
axios
.get(`${server}/images`)
.then((response) => {
console.log(response.data);
setData(response.data);
})
.catch((error) => {
console.log(error);
});
}
useEffect(() => {
getAllData();
},[]);
return (
<>
{api ? <Home data={data} /> : <p>Loading...</p>}
</>
)
}
export default ListImage
I am trying to implement Redux in a Next.js app and have problems getting the dispatch function to work in getInitialProps. The store is returned as undefined for some reason that I cannot figure out. I am using next-redux-wrapper. I have followed the documentation on next-redux-wrapper GitHub page but somewhere on the way it goes wrong. I know the code is working - I used axios to directly fetch the artPieces and then it worked just fine but I want to use Redux instead. I am changing an react/express.js app to a Next.js app where I will use the API for the basic server operations needed. This is just a small blog app.
Here is my store.js:
import { createStore } from 'redux';
import { createWrapper, HYDRATE } from 'next-redux-wrapper';
// create your reducer
const reducer = (state = { tick: 'init' }, action) => {
switch (action.type) {
case HYDRATE:
return { ...state, ...action.payload };
case 'TICK':
return { ...state, tick: action.payload };
default:
return state;
}
};
// create a makeStore function
const makeStore = (context) => createStore(reducer);
// export an assembled wrapper
export const wrapper = createWrapper(makeStore, { debug: true });
And here is the _app.js:
import './styles/globals.css';
import { wrapper } from '../store';
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}
export default wrapper.withRedux(MyApp);
And finally here is where it does not work. Trying to call dispatch on the context to a sub component to _app.js:
import React from 'react';
import { ArtPiecesContainer } from './../components/ArtPiecesContainer';
import { useDispatch } from 'react-redux';
import axios from 'axios';
import { getArtPieces } from '../reducers';
const Art = ({ data, error }) => {
return (
<>
<ArtPiecesContainer artPieces={data} />
</>
);
};
export default Art;
Art.getInitialProps = async ({ ctx }) => {
await ctx.dispatch(getArtPieces());
console.log('DATA FROM GETARTPIECES', data);
return { data: ctx.getState() };
};
This should probably work with "next-redux-wrapper": "^7.0.5"
_app.js
import { wrapper } from '../store'
import React from 'react';
import App from 'next/app';
class MyApp extends App {
static getInitialProps = wrapper.getInitialAppProps(store => async ({Component, ctx}) => {
return {
pageProps: {
// Call page-level getInitialProps
// DON'T FORGET TO PROVIDE STORE TO PAGE
...(Component.getInitialProps ? await Component.getInitialProps({...ctx, store}) : {}),
// Some custom thing for all pages
pathname: ctx.pathname,
},
};
});
render() {
const {Component, pageProps} = this.props;
return (
<Component {...pageProps} />
);
}
}
export default wrapper.withRedux(MyApp);
and Index.js
import { useEffect } from 'react'
import { useDispatch } from 'react-redux'
import { END } from 'redux-saga'
import { wrapper } from '../store'
import { loadData, startClock, tickClock } from '../actions'
import Page from '../components/page'
const Index = () => {
const dispatch = useDispatch()
useEffect(() => {
dispatch(startClock())
}, [dispatch])
return <Page title="Index Page" linkTo="/other" NavigateTo="Other Page" />
}
Index.getInitialProps = wrapper.getInitialPageProps(store => async (props) => {
store.dispatch(tickClock(false))
if (!store.getState().placeholderData) {
store.dispatch(loadData())
store.dispatch(END)
}
await store.sagaTask.toPromise()
});
export default Index
For the rest of the code you can refer to nextjs/examples/with-redux-saga, but now that I'm posting this answer they're using the older version on next-redux-wrapper ( version 6 ).
I am integrating redux with my react-native app. I have moved my state and action management to Container and integrated the container with component using 'connect'.
App.js
const AppNavigator = createSwitchNavigator({
SplashScreen: SplashScreen,
render() {
return(
<Provider store={store}>
<AppNavigator/>
</Provider>
)
}
});
const store = createStore(reducer);
export default createAppContainer(AppNavigator);
SignIn.js
import React from "react";
import {View} from "react-native";
import authenticateUser from "../../../services/api/authenticateUser";
const SignIn = (props) => {
const authenticate = async () => {
try {
return await authenticateUser.get('/abc', {
params: {
code,
}
});
}
catch (e) {
}
}
const validateUserCredentials = (isValid) => {
authenticate().then(response => {
const responseData = response.data;
props.updateEventRules(responseData);
});
}
}
return (
<View></View>
);
export default SignIn;
Sign-InContainer.js
import {eventRulesUpdated} from '../../../actions/actions';
import {connect} from 'react-redux';
import SignIn from './signin-screen';
const mapStateToProps = (state) => ({});
const mapDispatchToProps = dispatch => {
return {
updateEventRules: rules => {
dispatch(eventRulesUpdated(rules))
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SignIn);
When running the app I am getting an error that - props.updateEventRules() is not a function.
Can anyone please help me what am I doing wrong?
You should have the connect functions inside Signin.js like this
import React from "react";
import {View} from "react-native";
import authenticateUser from "../../../services/api/authenticateUser";
const SignIn = (props) => {
const authenticate = async () => {
try {
return await authenticateUser.get('/abc', {
params: {
code,
}
});
}
catch (e) {
}
}
const validateUserCredentials = (isValid) => {
authenticate().then(response => {
const responseData = response.data;
props.updateEventRules(responseData);
});
}
}
return (
<View></View>
);
const mapStateToProps = (state) => ({});
const mapDispatchToProps = dispatch => {
return {
updateEventRules: rules => {
dispatch(eventRulesUpdated(rules))
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SignIn);
I cannot able to access the data from the fetch function. I want to pass the data from action to reducer. API is called using an fetch function, api is returned in the form of promise. So, API is called separately and data is returned back to the action payload.
import { INDEX_PRESCRIPTION } from '../constant.js';
function fetch_prescription(){
const base_url= "http://192.168.1.22:3000/api/v1/";
const fetch_url = `${base_url}/prescriptions`;
let datas = [];
return fetch(fetch_url, {
method: "GET"
})
.then(response => response.json())
.then(data => {
datas.push(data['prescriptions'])
return datas
})
}
export const indexPrescription = async () => {
const action = {
type: INDEX_PRESCRIPTION,
details: await fetch_prescription()
}
return action;
console.log('action details', action.details)
}
export const getIndexPrescription = (dispatch) => {
dispatch(indexPrescription());
}
On examining the console, we get:
How to access the prescription details. I tried to access it by action.details["0"]["0"] , but results in 'Cannot read property "0" of undefined '. I have gone through many questions and solution related to this problem, but cant able to study what is going wrong with my code.
Update Here is my index.jsx component
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { getIndexPrescription } from '../actions/index.js';
class Index extends Component {
constructor(props){
super(props);
this.state = {
prescription: null
}
}
componentWillMount(){
this.props.getIndexPrescription();
}
render(){
return(
<h2>
Prescription Index
</h2>
)
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({ getIndexPrescription }, dispatch)
}
function mapStateToProps(state){
return {
prescription: state
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Index);
And My src/index.js file is
import React from 'react';
import ReactDOM from 'react-dom';
import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import {Provider} from 'react-redux';
import reducer from './reducers';
import Index from './components/index.jsx';
const store = createStore(reducer, applyMiddleware(thunk));
ReactDOM.render(
<Provider store={store}>
<Index />
</Provider>, document.getElementById("root")
)
Your promise is resolved only after you have answer from the server. You need to use additional layer in order to handle async behavior in redux.
For example with redux-thunk, you can make it work like this:
import { INDEX_PRESCRIPTION } from '../constant.js';
function fetch_prescription(){
const base_url= "http://192.168.1.22:3000/api/v1/";
const fetch_url = `${base_url}/prescriptions`;
let datas = [];
return fetch(fetch_url, {
method: "GET"
})
.then(response => response.json())
.then(data => data['prescriptions']);
}
export const indexPrescription = (dispatch) => {
fetch_prescription()
.then(details => {
const action = {
type: INDEX_PRESCRIPTION,
details
}
dispatch(action);
}
}
The part you are missing here is that the function fetch_prescription() is asynchronous. So the data may not be available when you are accessing the data.
You are returning the datas before resolving the asnyc function return datas
You may use it as
import { INDEX_PRESCRIPTION } from '../constant.js';
function fetch_prescription(){
const base_url= "http://192.168.1.22:3000/api/v1/";
const fetch_url = `${base_url}/prescriptions`;
let datas = [];
return fetch(fetch_url, {
method: "GET"
})
.then(response => response.json())
.then(data => {
datas.push(data['prescriptions'])
return datas
})
}
export const indexPrescription = async () => {
const action = {
type: INDEX_PRESCRIPTION,
details: await fetch_prescription()
}
return action;
}
export const getIndexPrescription = (dispatch) => {
dispatch(indexPrescription());
}
And dispatch the above action where ever you want.
Call getIndexPrescription() in componentWillMount
Find the code below to add redux-thunk to your application.
...
import { createStore, applyMiddleware } from 'redux';
import reduxThunk from 'redux-thunk';
...
const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore);
const store = createStoreWithMiddleware(reducers);
<Provider store={store}>
...
</Provider>