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).
Related
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.
I'm currently making a REACT web app, and I've made heavy use of localStorage to keep track of data without having to make more api calls, i'll provide a quick explanation of what i'm doing and would like to know if it's a good practice or if there's a better way.
I am working on a blog app and need to have access to some data in other components (such as the username of the currently connected user.)
So each time I make an api call, and receive data that I know I will need in other components (especially if it's not a child component of the one receiving the data), I store it in the localstorage so I can access it easily.
Is making use of the local storage everytime I need it for convenience good ?
Do you have any guidelines regarding when to query data instead of relying on localStorage ?
Thanks for your answer.
Remember that localstorage is persistent data. So it should be used for data that is required when the user leaves your app and comes back to it again.
On the other hand, sharing data between components while your app is running should be done with other mechanisms, typically passing props from a parent component to child components. Also, you can use React context or Redux or similar APIs to store data that is required globally while your app is running.
I would say "it depends"
If you are not accessing data in localStorage way too often, data inside of it are not changing frequently. Then it is OK. (still you need to have fallback for any other storage, try safari in anonymous window there localStorage does not work, old mobiles have limits how much data can be stored etc. etc.)
Otherwise it would be better use other means of storing data locally. Like IndexedDB, WebSQL. You can use some lib for managing those like for indexDB dexie, idb or any other.
If you are using localStorage just to ease your work with react props drilling, then rather use React.context, flux, redux... or any other state managment lib.
I’m using Redux to manage the logic of a music player. When it’s playing something and suddenly fails, I want to be able to intercept that action and make the player start again, but only n times, as I don't want to keep automatically retrying forever if the problem isn't recoverable.
I think a middleware is a good option to implement this, but I’m wondering if I should store the number of retries already done for a certain item either in the global state, or locally in the middleware.
A more general question would be if a Redux middleware should contain any local state at all, I mean, state that only it cares about.
In my opinion (and based on limited information about your specific project):
you should configure the n value via the middleware constructor, and
you should store both n and totalRetries in private variables of the middleware.
Why?
Choosing where to store your middleware state shares similarities with deciding between component state and redux state. You can use the same questions as a guide:
Do other parts of the application care about this data?
Do you need to be able to create further derived data based on this original data?
Is the same data being used to drive multiple components?
Is there value to you in being able to restore this state to a given point in time (ie, time travel debugging)?
Do you want to cache the data (ie, use what's in state if it's already there instead of re-requesting it)?
Do you want to keep this data consistent while hot-reloading UI components (which may lose their internal state when swapped)?
As Dan Abramov said:
The way I classify it is when ever state needs to be shared by multiple components or multiple pages and we need to persist some data over route changes, all that data should go inside the redux store.
You can map this idea from components to middleware by rephrasing "…persist some data over route changes…" to "…persist some data over [insert relevant boundary here]…", for example closing and relaunching the app.
The totalRetries doesn't seem to represent a meaningful state of the application. It has to do with some "behind-the-scenes" I/O operation that wont persist across closing the app or sharing app state with a debugger. One might even argue that you should not expose it to other components via redux state, lest they rely on (potentially shifting) internal workings of your middleware.
redux-saga, etc allow us to write this type of functionality in a very neat and testable way without having "exposed wires" in the application state or module namespace. You could use a saga to encapsulate your entire "play audio" behavior.
Exporting a reducer and then accessing its compartmentalized "public" state from your middleware introduces quite a bit of unnecessary complication.
If you want to expose totalRetries and n to other components, you may do so via an action, such as PLAY_AUDIO_RETRY with the action containing both variables in its payload.
I need to share some static data between my rails app and the redux-based front-end. The example in this case is a regular expression used by a helper method in the js and also in a controller in the rails app.
I feel it's annoying having to add something like this into the redux store since the store is not easily connected to from independent helper files in the js. Instead you would need to grab it in mapStateToProps, pass it as a prop into a presentational component, that would then send it through in an action, so that the code that handles actions (either in mapDispatchToProps or reducer) could send it through as a param when using the helper method.
Seems like a lot of unnecessary passing around for something that never changes. Are there any standards for static data provided by the server to be used in the front-end? Maybe adding something to the window object?
If its something that truly never changes, here are some ideas:
Have a configuration endpoint where you can get the regex and drop into redux state
Static config file that can be shared by JS/Ruby code
Hardcode the regex directly into the reducer's initialState
Create a javascript file and hardcode the regex directly into that file. Maybe put it in a file indicating its shared with the server.
Using the window object will make all serious react devs cringe a little. Eventually, that value could change, and it is going to cause bugs all over your app. If you are confident to make that gamble, then do it. Using the window object may make testing more difficult as well.
I have a complex form built with react-redux, and I need to know whether this form is valid from another javascript on the same page. Some jquery module.
The easiest way would be add valid/not_valid dynamic class to the react form, and to do something like
$('#myform').hasClass('valid')
But let's say that validation is not the only thing I need from this react app and I want to build a kind of interface for that with some getters. e.g.:
isValid(), getTitle, doSomethingElse methods.
what would be the right way to do that?
Ideally you would store any information you need outside the React application within the store, then simply access the store within whatever jQuery you are writing. This would also work going the other direction, update the store with any particular data that the React application might need to be aware of.
One possible approach:
You can try saving the reference to the store that you instantiate in a global variable.
E.g. Let's say in your top-level React compnonent App.js you do
import MyMainStore from '..../MyMainStore';
.
.
.
<Provider store={MyMainStore}>...</Provider>
//Then finally also do
_MyApp.ReduxStore = MyMainStore;
That way in the non-react/redux part of your app you can access the state via -
_MyApp.ReduxStore.getState().myFormReducer.someExpectedState
Look forward to hearing if that works for you.