Should I store static configuration in redux? - reactjs

I am building a react/redux web app and am wondering where I should static configuration information that never changes (while the webapp is running anyway).
This is the data in question
This information is used in different parts of the app, for example: there is a form where you are able to select any item out of the main array, and by doing so populating another select field with properties of the selected array:
<select>Choose an exchange</select>
<select>Choose a market (that is available in the above exchange)</select>
This would lend itself nicely to some reducer logic (that sets state.markets based on what is selected in the first select), but should it filter based on other state in the tree, or just load the data in a closure inside the reducer (keeping everything unrelated outside of state tree)? Or is this not state at all (and should the container load this file in and filter based on a single state.exchange state prop)?
When the form is filled in the result will be handled like:
{exchange: 'a', market: 'b'}
So that would be state too (I guess?)

My understanding of redux is that we should only be storing stateful data in the store, that is, data that is subject to change. Static data by definition does not have state, and therefore does not need to be tracked as such.
As a result, I typically have a /common/app-const.js file where I store these types of static objects. In your case, you can simply move all the static data from exchange.js into a common file that you then import wherever you need it.
/common/app-const.js
export default {
markets: [
{ pair: ['USD', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },
{ pair: ['RUR', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },
{ pair: ['EUR', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },
...
}
I understand your approach however, it would be nice to simply inject your data, by way of connect() via react-redux, however its a bit more straightforward to just import the static data from a file where needed.

Related

Updating Array of Objects in Firebase Realtime Database in React js

I have a problem with updating certain properties of an array of objects in a real-time database in Firebase.
My object looks like the following (see picture).
Now I want to update the IsComing property of the second participant object.
At the moment I use the updateIsComming() function, but this is not very convincing, because I have to rewrite the whole object.
function updateIsComming() {
const db = getDatabase();
update(ref(db, " your_path/EventModel/" + modelkey ), {
Location: "London",
Participants: [
{ Name: "Bella2", IsComming: "true" },
{ Name: "Tom", IsComing: "true" },
],
});
Instead, I just want to reference the specific prop from that array. For example
Participant[1].IsComming = false;
Is there any way I can access a specific array of an object directly.
Arrays as a data structure are not recommended in Firebase Realtime Database. To learn why, I recommend reading Best Practices: Arrays in Firebase.
One of the reasons for this is that you need to read the array to determine the index of the item to update. The pattern is:
Read the array from the database.
Update the necessary item(s) in the array in your application code.
Write the updated array back to the database.
As you already discovered, this is not ideal. As is common on NoSQL databases, consider an alternative data structure that better suits the use-case.
In this case, an alternative data structure to consider is:
Participants: {
"Bella2": true,
"Tom": true
}
In there, we use the name of the participant as the key which means:
Each participant can be present in the object only once, because keys in an object are by definition unique.
You can now update a user's status by their name with: update(db, "your_path/EventModel/" + modelkey + "/Participants/Tom", false).

How to use multiple ReactPixel.track('abc') inside one component?

I have a component on which I have to add two ReactPixel.track('abc') and
ReactPixel.track('cba'), how can I achieve this? Do I need to add just one ReactPixe.init('id') or two? Here is a code example:
componentDidMount() {
const options = {
autoConfig: false,
};
ReactPixel.init('123123', options);
ReactPixel.pageView();
ReactPixel.track('abc');
ReactPixel.track('cba');
}
You don't need to add multiple React inits on every page.
Just add it on your App.js(If you use create-react-app).
* You should initiate before you use it.
ReactPixel.init('123123', options);
If you need to get pageview details of whole app you need to use the below code.function in entry level.(I prefer after the init function)
ReactPixel.pageView();
There is no magic. It just call the same function that Facebook has given to you. fbq('track', 'PageView');
You can use track codes inside your functions. As a example after registration is successful you can create this track code.
ReactPixel.track('abc',{#data object goes here});
This is the example that Facebook has given.
fbq('track', 'Purchase',
// begin parameter object data
{
value: 115.00,
currency: 'USD',
contents: [
{
id: '301',
quantity: 1,
item_price: 85.00
},
{
id: '401',
quantity: 2,
item_price: 15.00
}],
content_type: 'product'
}
// end parameter object data
);
You can use this same function with react-facebook-pixel wrapper like this.
ReactPixel.track('abc',{#data object goes here});
Tracking Custom Events
You can track custom events by calling the pixel's fbq('trackCustom') function, with your custom event name and (optionally) a JSON object as its parameters. Just like standard events, you can call the fbq('trackCustom') function anywhere between your webpage's opening and closing tags, either when your page loads, or when a visitor performs an action like clicking a button.
For example, let's say you wanted to track visitors who share a promotion in order to get a discount. You could track them using a custom event like this:
fbq('trackCustom', 'ShareDiscount', {promotion: 'share_discount_10%'});
you can track custom events with react wrapper like this
ReactPixel.trackCustom(#title_of_event,#data_object);
If you need more understanding of what this react-facebook-pixel has done. You can read the code of the package.
https://github.com/zsajjad/react-facebook-pixel/blob/master/src/index.js
Facebook documentation: https://developers.facebook.com/docs/facebook-pixel/implementation/conversion-tracking#advanced_match

correct store structure when an action has child that needs to be retrieved with an action/api

I'm really new to react and I have a structure question...
I have the following structure:
cases:{
isFetching(pin):false,
isReady(pin):true,
errorMessage(pin):"",
list:{
0:{
id: "f8628ec8-5eRc-4d95-epj2-189ed8da",
userId(pin):"189ed8da-eff2-4d95-a76d-6fc794aa2bce"
name: "james",
photos:{
0:{},
1:{
userId(pin):"189ed8da-eff2-4d95-a76d-6fc794aa2bce"
timestamp(pin):"2016-07-20T15:32:59.034+0000"
id(pin):"b9628ec8-2efc-471c-8c84-16a7125d131e"
}
}
}
}
}
I retrieve the cases list with an action and store it in the react store, now eace one of the cases has a list of photos that the filePath needs to be retrieved and stored with a separate action/api.
Is it more correct to call filePaths action/api call separate completely form the cases action and store the result of the filePaths separate.
Or it could be a part of the cases action and stored as a child of a case photo? (meaning that I'll be able to do state.cases.list[0].photo[0].filePath).
what is the best way todo it?
Thanks.
Your method is correct We should try to avoid multiple API calls /requests as far as possible
Just do
state.cases.list[0].photo[0].filePath
to get your file parth

React/Flux app data structure

i'm building an Gmail-like email browser client app prototype and i need a little help/advice structuring my React/Flux app. I decided to use pure Flux to get a better idea of how it works.
It's a simple email client with a list of letters, grouped by folders and tags and an ability to add letters to favorites.
So, i have a LettersStore containing an array of letters. The single letter data object looks something like this
{
id: 0,
new: true, //unread
checked: false,
starred: false,
folder: "inbox", //could be 'sent', 'spam', 'drafts'
sender: "Sender Name",
subject: "Re:",
snippet: "Hello there, how are you...",
body: "Hello there, how are you doing, Mike?",
date: "02.19.2016 16:30",
tags:["personal", "urgent"]
}
So what i'm trying to achieve is to let users navigate through folders (inbox, sent, drafts, spam) and filters (starred, tag, etc.)
In both folders and filters there has to be a way to select (check) some/all letters. The view state depends on how many letters are selected (the Select-all checkbox update, just like on Gmail). When the user selects a letter, the Flux action is being triggered and the state of the app updates.
The controller-view on top of the app does all the calls to the LettersStore public methods and passes the data down as props, but i'm not sure, what public methods the LettersStore should have. Currently it has:
emitChange()
addChangeListener()
removeChangeListener()
getAll() //returns array
areSomeLettersInFolderChecked(folderName) //returns bool
areAllLettersInFolderChecked(folderName) //returns bool
countNewLettersInAllFolders() //returns object
This works ok with folders, but when it comes to filters, it doesn't make sense anymore, since a starred letter is in some folder, and i feel like it's not the right thing to add specific methods like areSomeLettersInFilterChecked(filterType) etc.
Also, just like in Gmail, there has to be a way to select letter in the "Starred" filter, which belongs to the "Inbox" folder, then navigate to "Inbox" folder and keep that letter selected.
Maybe i should move the areSomeLettersInFolderChecked-like stuff to the component level?
I'm sure here has to be a proper way of doing it. Thanks in advance!
Rather than trying to encapsulate all the possible states and filters into your letter objects, keep it dumb. Normalize it and use supporting data structures to represent the other characteristics.
I'd strip it down to just the following properties:
{
id: 0,
sender: "Sender Name",
subject: "Re:",
snippet: "Hello there, how are you...",
body: "Hello there, how are you doing, Mike?",
date: "02.19.2016 16:30",
tags:["personal", "urgent"]
}
Your LetterStore can stay the same, or alternatively you could use an object or map to store letters against their id's for quick lookups later.
Now we need to represent the properties we removed from the message.
We can use individual sets to determine whether a message belongs to the new, checked and starred categories.
For instance, to star a message, just add it's id to the starred set.
var starred = new Set();
starred.add(message.id);
You can easily check whether a message is starred later on.
function isStarred(message) {
return starred.has(message.id);
}
The pattern would be the same for checked and unread.
To represent folders you probably want to use a combination of objects and sets.
var folders = {
inbox: new Set(),
sent: new Set(),
spam: new Set(),
drafts: new Set()
}
Simplifying your structures into these sets makes designing queries quite easy. Here are some examples of the methods you talked about implemented with sets.
function checkAll() {
messages.forEach(function(message) {
checked.add(message.id);
});
return checked;
}
function isChecked(message) {
return checked.has(message.id);
}
function inFolder(name, message) {
return folders[name].has(message.id);
}
// is message checked and in inbox
if(isChecked(message) && inFolder('inbox', message)) {
// do something
}
It becomes easy to construct complex queries, simply by checking whether messages belong to multiple sets.

How to handle save states in React/Flux?

I've been working with react/flux for a few weeks now and while I feel like I've got a pretty good handle on everything from async loading to updating props/states/etc, one thing that is still bothering me is how to handle save states.
For example, when loading data, I just have an isLoading boolean parameter in my store that gets passed to my components. But when I try and post an updated object to the server, it's trivial to:
fire the update action
display a "save in progress" state
but figuring out the result of the update action seems to be way more difficult.
Probably the most applicable post I've seen on this is in Fluxxor's async data guide, but their solution (adding/modifying a status property on the object) feels error-prone to me.
onAddBuzz: function(payload) {
var word = {id: payload.id, word: payload.word, status: "ADDING"};
this.words[payload.id] = word;
this.emit("change");
},
onAddBuzzSuccess: function(payload) {
this.words[payload.id].status = "OK";
this.emit("change");
},
onAddBuzzFail: function(payload) {
this.words[payload.id].status = "ERROR";
this.words[payload.id].error = payload.error;
this.emit("change");
}
Is there a better way to manage save states or is adding a status property to the object the best way?
I recommend keeping your "model stores" and "ui stores" separate, or at least accessed via different cursor positions in the same store. So, in your case you'd have one store or branch for your "word model" and then another store or branch for "word status."
While this adds some complexity in the form of breaking up logic across stores and reacting twice to the AddBuzz action, it ends up reducing (more) complexity by confining model store updates to true changes in model data and managing ui states separately.
EDIT
This is what Relay will more-or-less be doing, keeping persisted data in a separate self-managed store, leaving custom stores for nothing but ui state. Some other libraries like https://github.com/Yomguithereal/baobab also recommend this approach. The idea is that these are fundamentally different kinds of state. One is domain-specific persisted data and the other is ui-specific ephemeral application state.
It might look something like this:
model_store.js:
onAddBuzz: function(payload) {
var word = {id: payload.id, word: payload.word};
this.words[payload.id] = word;
this.emit("change");
}
ui_store.js:
onAddBuzz: function(payload) {
this.wordStates[payload.id] = 'ADDING';
this.emit("change");
}
my_view_controller.js:
// listen to both stores and pass down both words and wordStates to your views
my_word_view.js:
...
render: function() {
var word = this.props.word,
wordState = this.props.wordState;
...
}
If you don't want to emit two change events, have one waitFor the other and emit the change only from the second one.

Resources