Calling API via redux in react app does not work - reactjs

I am building a web app with MERN stack and using redux as the state management. I am now trying to load the data from mongoDB with my API and storing into redux before setting into react state. When calling the api with getShop() function directly from react app, the data is stored in react state and displayed in the app. However it does not work when i am trying to use it through redux as per my below codes. There are no errors, but just not loading any information.
Action:
load : () => {
let thunk = (dispatch) => {
api.getShops()
.then(res => {
let barbershops = res.data
dispatch(barberFactory.set(barbershops))
})
}
return thunk
},
calling from react app:
function mapDispatchToProps(dispatch){
return {
loadBarber : () => {
dispatch(barberFactory.load)
},
}
}
The function is called at componentDidMount()

Your load function needs to be called in order to return the inner action i.e.
dispatch(barberFactory.load())

Related

intergation of flask for ML into a meteor.js app

I have build a simple pure react and meteor web app. I am trying to connect a flask API to my meteor.js app for the machine learning component of my application. I have seen examples for pure react front end but cant get the same logic to work for meteor.
what I did is:
make a flask app and return the prediction results to localhost:5000 as a python dictionary e.g.
{'class': 'bird', 'confidence':'0.8932'}
Set up a proxy in my meteor app in package.json, I have meteor app running at localhost:3000:
"proxy":"http://127.0.0.1:5000/"
finally, this is where I am confused, I have a bunch of components in my home page, I am not sure if I have to render the flask results in a component or page, nor how to do that. What I tried Is to render the results in one of the components using the useEffect, useState functions.
I get an error that says something like I can't use this funtionality.
function App() {
const [predictedClass, setPredictedClass] = useState(0);
useEffect(() => {
fetch('/prediction').then(res => res.json()).then(data => {
setPredictedClass(data.class);
});
}, []);
I use the useEffect method to get the data from the requests of my api.
example:
const [data, setData] = useState(null);
useEffect(() => {
getData('GET', '/api/test')
.then(response => {
setData(response)
})
.catch(error =>
console.log(error)
);
}, []);
Where getData is a custom function that calls an axios request.

When to use Redux to fetch data from api call

I adopted Redux in my project for state control, and also Axios for fetching api in action.
But I wonder when should I fetch data using API call through Redux (in action), when should I directly make the api call in component.
Is it depending on, whether I need to store the response data in Redux (for sharing among different components)? May I know any best practice for it?
API call through Redux
export const fetchOptions = () => {
return async (dispatch, getState) => {
const request = await client.query({
query: gqlQueries.getQuery,
});
const options = await request;
dispatch({
type: types.FETCH_DATA_END,
options: options
});
}
}
Directly make API call in component:
const axios = require("axios");
useEffect(() => {
axios({
url: 'http://localhost/graphql',
method: 'post',
data: {
query: `
query PostsForAuthor {
author(id: 1) {
firstName
posts {
title
votes
}
}
}
`
}
}).then((result) => {
console.log(result.data)
});
}, []);
If multiple components are using the same data, redux shines there. API calls in components are preferred when you do not want any stale data to show, therefore you call api every time component mounts and your data is always in sync with your back end. There might be some other criteria but these two help me decide , where to keep the state.

how to load a function when a page load react native

I'm using react-native with hooks, and I'm trying to load a JSON from AsyncStorage every time a user opens one of my react-native screens This JSON contains information on what my states should be set to.
How can I call a function that runs every time this screen is opened?
i know that without hooks this should be done with useEffect, but when i put my api call there it makes an error
this is my code
useEffect(() => {
const getKind = () => {
ForceApi.post(`/GetKindPensionController.php`)
.then(res => {
setpPensionKind(res.data.pension);
})
}
}, []);
You are missing call the getKind, and it should be a async function! For a better code try something like:
useEffect(() => {
async function getKind() {
const { data } = await ForceApi.post(`/GetKindPensionController.php`)
setpPensionKind(data.pension);
}
getKind();
}, []);

React Redux Saga boilerplate flow

I have started my react.js project using one of Starter kit. I have used one Boilerplate structure. I am trying to learn the actual flow of React
Redux Boilerplate. After gone through their structure I am able to call the API and got data on Component. Here is the flow what I have learned as per the structure:-
a. On componentDidMount I have called a method of Mudules to create an Action.
// On view
componentDidMount() {
this.props.getCampaignTopics(1);
}
//On Modules
export const getCampaignTopics = createAction(GET_CAMPAIGN_TOPICS, (id : string) => ({id}));
b. On saga when action has been fired, I am calling the API endpoint to get the data
// On Saga
export function* getCampaignTopics(actions) {
let id=0;
if(actions.payload.id)
{
id= actions.payload.id;
}
const responsetype = yield call(() => fetch(__CONFIG__.api_url+'topic/' + id,{method:'GET',data:{}}).then(response => response.json()))
yield put(addcampaignActions.setCampaignTopics(responsetype.data));
}
function* watchGetHome() {
yield takeLatest(addcampaignConstants.GET_CAMPAIGN_TOPICS, getCampaignTopics);
}
c. After Getting the data I am calling another method of Modules to set data
export const setCampaignTopics = createAction(SET_CAMPAIGN_TOPICS, (topics : any) => ({topics}));
export const reducers = {
[GET_CAMPAIGN_TOPICS]: (state, { payload }) =>
state.merge({
...payload,
}),
[SET_CAMPAIGN_TOPICS]: (state, { payload }) =>
state.merge({
...payload,
}),
}
d. In View I am using selector to separate the indexes
// Selector
const addcampaignDataSelector = state => state.addcampaign;
const topicSelector = createSelector(
addcampaignDataSelector,
payload => payload.get('topics')
);
export const addcampaignSelector = state => ({
topics: topicSelector(state)
});
e. In component I am getting the value on props
// render on Component
const { addcampaign } = this.props;
topics = addcampaign.topics.toJS().children;
So, that's the flow I have got from their tutorial and I am getting the data. But I want to make sure I am on right track or not? Please tell me this is the right process or not?
Next is I want to call a method from component and want receive the response on the component, so I can get the data on a local variable. Could anyone can give me some tutorial or example, So I can go through and learn easily.
If your looking for a production ready boilerplate,
react-boilerplate is one of the popular ones.
You seem to be on the right track. This diagram from react boilerplate guide might help in understanding the flow better.

How to synchronize Redux and Relay?

The situation
I have an onboarding scenario where the user goes through a step-by-step onboarding. I want to manage the client side state of the user's progress with Redux. The synchronization between the server and the client is already implemented in Relay, but I still need a Redux store for client-side state management. As such, problems arise with synchronizing the Relay-/Redux-Store.
What I'm doing right now is to wrap my React component with Redux and then with Relay:
// OnboardProgressView.js
// ...
// wrap React component with Redux
const mapStateToProps = (state) => {
return {
onboardProgress: state.onboardProgress,
}
}
const ReduxContainer = connect(
mapStateToProps,
)(OnboardProgressView)
// this is only for convenience of access of the Relay data
const MappedOnboardProgressView = mapProps({
params: (props) => props.params,
user: (props) => props.viewer.user,
})(ReduxContainer)
// wrap Redux component with Relay
export default Relay.createContainer(MappedGettingStartedView, {
fragments: {
viewer: () => Relay.QL`
fragment on Viewer {
user {
userId
onboardProgressStep
}
# more stuff ...
}
`,
},
})
My progress
I have found ways to accomplish different operations as follows:
Initialization of the Redux store with server data
I am initializing the Redux state right after creating the store with an asynchronous raw Relay query. To make that possible I am also using the redux-thunk middleware. Redux initiates a request to Relay which queries the server. Visual representation (an arrow denotes data flow, the order of elements reflects the 'call order'): Redux <= Relay <= Server
// app.js
const store = createStore(reducer, applyMiddleware(thunk))
store.dispatch(fetchOnboardProgress())
// onboardProgress.js
export function fetchOnboardProgress () {
return function (dispatch) {
var query = Relay.createQuery(Relay.QL`
query {
viewer {
user {
id
onboardProgress
}
}
}`, {})
return new Promise(function (resolve, reject) {
Relay.Store.primeCache({query}, ({done, error}) => {
if (done) {
const data = Relay.Store.readQuery(query)[0]
dispatch(update(data.user.onboardProgress, data.user.id))
resolve()
} else if (error) {
reject(Error('Error when fetching onboardProgress'))
}
})
})
}
}
Updating data on server when dispatching a Redux action
Redux => Relay => Server
To have consistent state changes, when the user progresses through the onboarding process, I fire a Redux action that will also asynchronously do a Relay mutation. I am also using redux-thunk for this purpose.
function nextStep () {
return function (dispatch, getState) {
const currentStep = getState().onboardProgress.step
const currentStepIndex = OnboardProgress.steps.indexOf(currentStep)
const nextStep = OnboardProgress.steps[currentStepIndex + 1]
const userId = getState().onboardProgress._userId
return _updateReduxAndRelay(dispatch, nextStep, userId)
}
}
function _updateReduxAndRelay (dispatch, step, userId) {
return new Promise((resolve, reject) => {
Relay.Store.commitUpdate(new UpdateUserMutation({
userId: userId,
onboardProgressStep: step,
}), {
onSuccess: () => {
dispatch(update(step, userId))
resolve()
},
onFailure: reject,
})
})
}
export function update (step, userId) {
const payload = {onboardProgress: new OnboardProgress({step, userId})}
return {type: UPDATE, payload}
}
Open Problems
I still haven't find an approach to the following situation:
Updating the Redux Store when the Relay Store updates
Changes to data on the server might have external sources, that are not triggered by a user action in our app. With Relay we can solve this with forceFetching or polling. A Relay query looks like this: Relay <= Server. I'd like to additionally have this data flow: Relay => Redux when external data changes.
Another possible reason for the need to update the Redux store with new data is when we want to synchronize data that is deeply nested in the Relay store, or part of a complex query.
For example, think of the count of comments to a blog post. When a user is posting a new comment, another component showing the comment count should update as well.
If we manage this information in Redux, we need a way to trigger a Redux action when a Relay query comes with new information. I am not aware of such a callback, or another solution to this situation.
My Questions
In this context, I have those questions:
What can I improve in my existing approaches? Is there something I did that is highly dangerous/leads to inconsistencies? (see My Progress)
How can I manage to sync the Redux store when for some reason the Relay store is being updated. I am looking for a React component life cycle method or a Relay callback where I can then send a Redux action to the Redux store. (see Open Problems)
RelayNetworkLayer is what you should use to sync the redux store with the relay one as it allows you to subscribe to everything that happens there. I'll update this post later if anything else comes to mind.

Resources