Load JSON data in my initital state - javascript

I try to learn React.js but I have some difficulties to load data from my server with redux. For the moment my global state is loaded with static json like this:
My store.js
import ...
// Load my static json data
import tickets from '../data/tickets.js'
import interventions from '../data/interventions.js'
const defaultState = {
tickets,
interventions
}
const store = createStore(rootReducer, defaultState);
export const history = syncHistoryWithStore(browserHistory, store);
export default store;
My application works perfectly. Now I want to fill my components with the data returned from my node.js server. However I have no idea how to corretly do it.
I have to fill my defaultState only once ? After the reducers will change the values ?
Is isomorphic-fetch is a good way to call a url from my server ? (I use react-router on my client)
Thanks for your answers.

if you try to do this on client side you would be asynchronous.
On your entry point, where you are importing the store, you can fetch your data then dispatch an action that will init your tickets or interventions.
You can also use redux-async-connect to give your app all required data before it's will be mounted, this can be use also on server rendering side

Related

Vuex with Nuxt - Unknown Action Type:

I am trying to move my local methods to a VueX Store. Im using nuxt.js so the store format is a bit different than usual. When I try to call my store action, i get "vuex unknown action type: fetchProducts". Its gotta be something to do with how im calling the store, but I havent quite figured it out.
So, Nuxt uses the store folder system, and I call to import map actions -
import { mapActions } from 'vuex';
then in my methods, I list map actions alongside the directory the method exists in an index.js file.
...mapActions('RyansBag/Inventory', [
'fetchProducts',
]),
in the same methods, I request to start pulling the data from the store from this method, which is mounted.
async getProducts(){
this.TableData.isLoading = true;
await this.$store.dispatch('fetchProducts', this.options);
this.TableData.isLoading = false;
},
my understanding is in nuxt i dont have to call an action by its module name - which nothing is in module - I think? Unless store folder system in nuxt is considered modules which I may have misunderstood.
for the fetch request, it should have been this.fetchProducts() instead of a string reference. Fixed. :)

Can I use _app.js to share data globally in my app?

I'm building a small chat app that will use sockets.
Thus I need to use both Context API and a global socket variable. This is my first project using Next.js and I'm not sure how the data flows here.
Beforehand, I used to pass props to the component with React router, however I came to realize that it's not possible with Next.js.
so, my question is whether I'm sharing the socket object correctly.
if that is not the case I would highly appreciate it if you can share with me a code snippet of the right implementation of Sockets utilizing Next.js
My _app.js file:
import { createContext } from 'react';
import '../styles/globals.css'
import UserRoom from '../context/state';
import { useState } from 'react';
function MyApp({ Component, pageProps }) {
const [userName, setUserName] = useState('');
const [userRoom, setUserRoom] = useState('');
const socket = io.connect('http://localhost:4000', { transports : ['websocket'] });
return(
<UserRoom.Provider value={{userName, userRoom, setUserName, setUserRoom}}>
<Component {...pageProps} />
</UserRoom.Provider>
)
}
export default MyApp
The answer is Yes you can, you can share all global states inside _app file, but it will affect to all the components, including the server-side component and the client side, if something depends on the client it will throw an error because window is undefined.
and for the information, this is how next js Data-fetching props flow all work :
Data Fetching > _app > components inside pages
read more here

Send data between components in ReactJs using Apollo Client

According to the documentation, GraphQl provides state management like Redux. I have 2 components. In the Component1 i get data from the server using AppoloClient, it works ok, and in the Component2 i want to read data from the cache(store).
//Component1
import React from "react";
import { gql, useQuery } from "#apollo/client";
const EXCHANGE_RATES = gql`
query GetExchangeRates {
rates(currency: "EUR") {
currency
}
}
`;
const Component1 = () => {
const { loading, error, data } = useQuery(EXCHANGE_RATES);
console.log("component1", data);
return <div>Component1</div>;
};
export default Component1;
//Component2
import React from 'react';
import {gql} from "#apollo/client";
import {client} from "./App";
const Component2 = () => {
const info = client.readQuery({
query: gql`
query EXCHANGE_RATES {
rates(currency: "EUR") {
currency
}
}
`,
});
console.log('component2',info);
return (
<div>
component2
</div>
);
};
export default Component2;
Issue: I can get data in component 1, but when I try to read data from component 2, I get undefined.
Question: How to solve this to be able to read data that is fetched in component 1, in component 2? Also how in GraphQl and Apollo client to pass an object for example in the cache, and to read this in component 1(like redux functionality)?
demo: https://codesandbox.io/s/empty-sun-symv6?file=/src/App.js
When the App mounts, both of your component's data are empty.
Then apollo fetches the data with useQuery. And your component1's state got changed. Because of that, component1 re-render and log the new data.
But there is no state on your component2 that changed. So, component2 does not re-render.
To solve this, you can run useQuery hook with the same query on the component2 again, by default apollo will provide you the data from the Cache.
Apollo provides client-side state handling which can be set up to handle your client site state in the same we you do it with your server-side state.
In your example this is not what you want. Recently there is a noticeable shift in the react community that server side data should not be stored in your global state handling tool of choice. Your fetching tool (in your case apollo) should handle this by caching the responses.
To solve your problem, where both components are using the exact same query, you should just do that. Run the query twice and let apollo handle the caching. So you could pull out the query to a query file or just create a useRates hook and import that in your component to even better share the logic between your components.
To answer why your approach is not working you have to understand that your lookup in the cache is happening at a time before your request has even finished and that this cache look up is not "reactive".
Edit: I just got this out fast to provide a starting point and can clean this up later if things got cleared up.

Use Redux state to initialize Axios client

I have a React/Electron application I'm working on in which I want to use data from my Redux store to initialize my Axios client. The use case is, for example, on first load of the app the user enters some information, like their username. This is pushed to the Redux store (and persisted in localStorage for future use), then used in the baseURL of the axios client for subsequent network requests.
The problem is, I can't get axios to work with react-redux and the connect() function. Axios' function exports seem to be hidden by the exported HOC, and any time I call one of its functions I get the following error:
TypeError: _Client2.default.get is not a function
My client looks something like this:
import axios from "axios";
import { connect } from "react-redux";
const Client = ({ init }) => {
return axios.create({
baseURL: `http://${init.ip}/api/${init.username}`
});
};
const mapStateToProps = state => {
return { init: state.init };
};
export default connect(
mapStateToProps,
{}
)(Client);
What am I doing wrong here?
Here in react-redux documentation https://react-redux.js.org/api/connect#connect-returns it says that The return of connect() is a wrapper function that takes your component and returns a wrapper component with the additional props it injects. So it returns react component that wraps react component. Your function returns axios client, it doesn't render anything.
I prefer to use action creators and make api calls there(Therefore I don't pass axios client or whatever). But if I decided to that I would initialize axios client inside reducer and keep in the store. And then pass it to clients as props.
const mapStateToProps = state => {
return { axios: state.axios };
};
On top of #Ozan's answer, In this case what you can do is create a main component, connect it with redux and dispatch an action on mount to initialize axios client.
You should initiate AXIOS client before you load App.js. I recommend you can use redux-axios as redux middleware and use action to call api.
https://github.com/svrcekmichal/redux-axios-middleware

Getting router params into Vuex actions

I would like to pass router params into Vuex actions, without having to fetch them for every single action in a large form like so:
edit_sport_type({ rootState, state, commit }, event) {
const sportName = rootState.route.params.sportName <-------
const payload = {sportName, event} <-------
commit(types.EDIT_SPORT_TYPE, payload)
},
Or like so,
edit_sport_type({ state, commit, getters }, event) {
const payload = {sportName, getters.getSportName} <-------
commit(types.EDIT_SPORT_TYPE, payload)
},
Or even worse: grabbing params from component props and passing them to dispatch, for every dispatch.
Is there a way to abstract this for a large set of actions?
Or perhaps an alternative approach within mutations themselves?
To get params from vuex store action, import your vue-router's instance, then access params of the router instance from your vuex store via the router.currentRoute object.
Sample implementation below:
router at src/router/index.js:
import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './routes'
Vue.use(VueRouter)
const router = new VueRouter({
mode: 'history',
routes
})
export default router
import the router at vuex store:
import router from '#/router'
then access params at vuex action function, in this case "id", like below:
router.currentRoute.params.id
Not sure to understand well your question, but :
This plugin keeps your router' state and your store in sync :
https://github.com/vuejs/vuex-router-sync
and it sounds like what you are looking for.
To my knowledge ( and I've looked into this for a project I'm working on ) no, there is not.
The simplest way to do this is to abstract route fetching or anything you want to do to a service and use it in your vuex file or if you use modular approach import it in you actions.js file.
so paramFetching.js file would look like this:
export default {
fetchRouteParams: function() {
// do fetching
// you should return a promise
}
}
Then import that into your vuex
import service from 'paramFetching.js'
And then make an action like so
...
fetchParamsAction: function({commit}) {
service.fetchRouteParams()
.then( (response) => { // stuff gottten from service. you should o your commit here } )
.catch( (error) => { // error handling } )
}
And then just dispatch this action and everything will be handled in an action. So it kinda isolates that from the rest of the code.
This is just a general idea. I'm sorry if it's not clear enough. If I can help further, please ask.
You can use this function to get params into Vuex
import router from './router';
router.onReady(()=>{
console.log(router.currentRoute.params.sportName)
})

Categories