When your API is not ready - React + Redux + Axios - reactjs

This question may be vague, but I thought would help organize my thoughts:
I am setting up the Redux store for a project. Along with the store setup I am setting up an endpoint I have the swagger file for. However, the API is not live just yet. I was wondering how do I set this up with test data in the meantime so when the API is ready, I am able to quickly update.

I would define a Client class or object that interacts with your API. Maybe it has specific functions like .getUser(id) or maybe they are move vague like .getEntity('user', id). This provides a layer of abstraction so that instead of calling axios.get('my-api/users/${id}') in your thunk actions you can call client.getUser(id).
You will have two separate versions of a Client that fit the same interface (this is a lot easier to enforce if using typescript). One will query your actual API while the other just returns mock data. Since they both act the same, it should be easy to switch from one to the other when you are ready. You will have some file where you create and export a client variable.
export const client = new APIClient();
or
export const client = new MockClient();
When you import this client to use in other files, it shouldn't matter which one it is because they both share the same Client interface.

Related

Redux Toolkit: What is the Preferred Method for Data Fetching?

I'm currently using React (with hooks) and Redux-Toolkit. After reading through the docs, I've come across Redux Thunks, createAsyncThunk, and RTK Query. Out of these three methods, which is the best for fetching data in a Redux slice, modifying that data within the slice, and then dispatching said data to a React?
Thanks in advance for your answers!
Each of them serves its own purpose, and only RTK-Q is made exactly for data fetching and caching.
The "problem" is that it's
Not really integrated with the application store's Redux and Thunks by default - it "lives" in its own store, with its own cache state, actions, and middleware.
The idea is that you don't want to put fetched data in your app-store, course, it will just duplicate the data and add another "source of truth" with the following inconsistency.
RKT-Q adds a concept of "API state", which represents the data on the backend, and should be handled significantly differently than App's (frontend) state.
In extra cases, you may handle the RTK-Q-related actions, handle them in your middleware (Thunks in your case) and update your Redux app-state producing actions with some calculated data\flags, etc.
Not covering all the cases of Application <-> API negotiation.
As an example - file\data export, API action calls, and other stuff that is out of RESTfull architecture. If you'll try to download a file from API via RTK-Q you'll find how bad it's covering such a case, and you'll be forced to use separate flow via Thunks\Sagas or\with plain fetch API to do so.
But still, RTK-Q brings you so much out of the box, so it is worth using it by default for data fetching, even with some work to handle several edge cases.
Wrapping up - I believe that there is no right\complete answer to your question and just more things to consider for your own app architecture design.

Store complex APIs objects and allow access from components and redux

I tried searching for "good practices" about how to link complex APIs that needs configuration or be provided by some manager and I can't seem to find how to make a "good" flow of data through redux.
So far I have been thinking of creating a reducer with actions that map each method I can call on a given complex object.
To put more context to it, I am building a framework to interact with a bluetooth device using this library (https://github.com/Polidea/react-native-ble-plx) and the startScanDevice returns me complex objects I can interact with (https://polidea.github.io/react-native-ble-plx/#device) which also holds it's own state (a device knows if it's connected or not for instance, it also knows it's bluetooth services, etc.).
From what I have read, redux state should be having simple objects so it can have time travel properties and ease persistence.
What would be a good design to to store those complex objects and enable interaction between my components, reducers, actions, the store and this API I'm currently working on ?
Currently, I was thinking of giving callbacks to my API that would dispatch redux actions with new data to add in the redux store but I just can't seem to find a proper way to store my complex objects and provide access to it in order to invoke those methods and give them callbacks.
Here's a complete flow example :
Invoking startScanDevice from the plx-ble API and provide a callback to receive device object given by that existing API
receive device objects and store it somewhere
Update redux store with proper information about the device object I need throughout the app
From a reducer, retrieve the device object from step 2 and invoke a method to interact with the device (example read from a characteristic)
Update redux store with read data from step 4
Steps 2 and 4 are the ones I can't seem to find a proper way to do.
Any help would be greatly appreciated !
Redux-thunk middleware could be helpful to you.
Redux Thunk middleware allows you to write action creators that return
a function instead of an action. The thunk can be used to delay the
dispatch of an action, or to dispatch only if a certain condition is
met. The inner function receives the store methods dispatch and
getState as parameters.
to store those complex objects
Don't complicate this.Try to keep your state as flat as possible.
Like
state={
PoweredOn: false,
Device: "deviceName",
//similarly all
}
The more you keep it flat the more it will be easy to modify.
The API doc you linked seems to have duplicate ways of calling these methods for exactly this reason.
For instance, you could connect to the device by calling device.connect(options) or by calling the package method connectToDevice(deviceId, options). The benefit of the second method being that you only need to track the ID value, and have no need to store the entire device object.

Using react to reflect external changes from the data layer

I'm not a frontend developer and have not used react or any flux implementations as I'm not sure if they will do what I want. I'm trying to wrap my head around how to use react to render backend changes that are external to the client, ie changes by another user. I see how react works to handle the view when the client takes an action, but I'd like to render changes from the server/other users without long polling (similar to how meteor works with two-way data binding).
My solution was to create a pub/sub system on the backend that will push changes to the clients if they're subscribed to the appropriate channel. This could be accomplished by analyzing database queries/backend actions and their resulting changes as is done with Asana's Luna. My friend told me that I can simply do this with only using an implementation of flux. If he's correct, I must be misunderstanding what flux actually does. To me, it seemed that it only reflects changes based on the actions of the 'current' client.
You are right. Flux is simply a way to manage application state in response to different actions. How you would trigger those actions is out of its concern. pub/sub server in this situation is a right way to go. You can take a look at Firebase - google non relational database that has lots of SDKs for different platforms and can notify client of changes done by other users. But anyway it works as a pub/sub server =)

Storing "global" object outside of Redux store in React/Redux app

I am building a React/Redux app that needs a globally available object (a websocket lib instance). I originally tried to store this in the Redux state tree, however, the instance is not immutable and it caused lots of problems with hot reloading during development (tons of circular reference errors that don't exist when running from compiled code).
My question is how to store/create this instance so that it is available to my Redux code and React components? I could create it at the very top of the component tree and pass it down the tree as a prop, but that feels very "dirty" after doing everything with react-redux connect.
Is there a better way to do this?
#sheeldotme's answer will work well if you're using thunks.
Also keep in mind that, depending on the websocket lib you're using, you may not need the instance as a global variable. For example, with socket.io-client, after your initial io(url) call that makes the websocket connection, any subsequent calls to io(url) (with the same url argument) will return that same connection (i.e. socket object) from memory, without having to reconnect. It makes it easy to have an API that you can simply import/require, rather than having to pass the instance around or make it global. See the socket.io docs for more info.
For example:
socket.js
import io from 'socket.io-client'
const socket = io(`${protocol}//${hostname}:${port}`)
export default socket
Now you can simply import/require your socket.js file to have easy access to the same socket object from anywhere.
Redux Thunk, authored by gaeron, he who authored redux, since 2.1.0 allows you to do:
const store = createStore(
reducer,
applyMiddleware(thunk.withExtraArgument(api))
)
// later
function fetchUser(id) {
return (dispatch, getState, api) => {
// you can use api here
}
}
This is straight from the docs, see the link below for more information:
https://github.com/gaearon/redux-thunk

How to pass application settings to store

In terms of clean react application design, I'm sure sure how to pass around application settings to modules which are not part of the component tree.
E.g. I connect to a REST API and therefore need to propagate the hostname to the components, but also to the store - I'm using Reflux.
Passing the setting down to components can be easily achieved via contexts, but since the store is not part of it, what's the cleanest way?
So far, I consider these approaches:
Passing the setting from the component to the action, to that I receive it on every store listener.
Use some DI container which is initialized in my index.js and can be used in my store
Both don't seem to be ideal for me. Any hints appreciated!
In most cases you should not keep application settings in store.
You should think about your application like some kind of function that receives state as parameter and returns view. Changes in application state (usually) lead to changes in resulting view. Flux stores are the way you're keeping this state. API hostname is not that stuff which you expect to affect your application. It is just an information payload that your app need to know to work correctly (say configuration, not the settings). So, you should keep it as information payload. Module, class, global variable, some kind of DI, you can consider anything that you find useful to work with.
I usually create separate module exporting object with all configuration. Something like:
const config = {
api: {
hostname: 'localhost',
port: 3000
}
// ...
};
export default config;
And then just importing it. Something like:
import config from "../config";
const api = new API(config.api); // just for example
But if you really need to work with some kind of settings that can affect UI (an example is delay to show popup; it example can be even better if we consider changing this delay depends on user's actions) you should create Settings store and work with it like with a regular flux store (subscribing to change, changing with actions so on).

Resources