I'm trying to build a complex fully-dynamic app with Redux. I mean my App has lots of dynamic-generated forms with generated fields-components on-the-fly. I want to store in my Redux-store visual data about my components too. But how should i do it without mixing real data with visual component data?
For example if i have structure like this
Store {
visual: {...deeply nested visual-data-tree...},
data: {...deeply-nested real-data-tree...}
}
It is hard to render component because i need to search visual data first, then react component "value" in two trees.
But if have a structure similar to this:
Store {
form {
visual: {...form visual data...},
data: {
//Ok here the form "data" - widgets. Or it must to be visual? :)
widget1 {
visual: {type:"ComboBox", opened: true},
data: 1
}
}
}
}
You see the problem, now i have visual data inside real data of Form widget.
(form - data - widget1 - visual)
Visual data inside the real data is out of the concept.
How do you guys solve same problems of mixing data?
Really sorry for my poor english. I hope i clearly explained the problem.
Isn't the distinction superficial? I think a more important rule is that the data in the state should be normalized. For example, if you have Combobox widget letting you choose users, your data shape better be
{
chosenUserId: 10, // Good!
users: {
10: { name: 'Alice' }
}
rather than
{
chosenUser: { name: 'Alice' }, // Bad!
users: {
10: { name: 'Alice' }
}
If the data is duplicated in the state tree, it's hard to update it correctly and avoid inconsistencies.
As long as you keep the data normalized, I see no real need to divide visual and data. You might want to have top-level entity cache that looks like a database (e.g. entities which includes users, posts, or whatever data objects your app uses), but other than that, go with whatever state shape feels most comfortable when retrieving the relevant state.
Related
What I'm building
There is this game Path of Exile, that has a passive tree that i'm recreating in my Vue application with some help from Pixi Js. The game developers release a json with the data for this passive tree every expansion for people to work with.
The Tree: https://www.pathofexile.com/passive-skill-tree
The json: shorturl.at/gBSV5 (Don't forget to press the "View raw" link)
My problem
I got the tree component working, but since the json is quite large the app.js is also very large when i build for production. This is not that great for the performance and i'm looking to improve this.
Vue Project
My tree component looks something like shown below. So i'm using the json file to do various things so i can draw the tree on my canvas correctly.
import json from "#/data/data.json"
import * as PIXI from 'pixi.js'
export default {
name: "Tree",
data() {
return {
treeData: {},
};
},
mounted() {
this.treeData = json
this.drawTree()
},
methods: {
drawTree () {
// Calculate size of the tree
// Make some containers
// Loop all nodes on the tree and draw them
// Calculate connections between nodes and draw them
// Some more stuff...
}
}
}
The solution?
I'm accessing the data from the json all the time in my code, so i don't really know where i can win performance if in the end i need all the data and this all will be in my app.js. So how should i go about working with this data? Is it maybe better to store it in a (mongoDB) database or would that result in the same problem?
I'm trying to query my Firebase Realtime Database to find all games a user belongs to.
I have a list of games, each game has a property of players. Each child of players has a key of $uid, and within that {key: $uid, name: "joe"}
Is it possible to get all games this way? Or do I need to start keeping another index of players_games/$uid/$game?
I've tried firebase.database().ref('games').orderByChild('players').equalTo(token.uid), but this yields null
It looks like database.ref('games').orderByChild('players/${token.uid}') works, but then I'd need to give .read access to all of games, or do this server-side.
Your current data structure makes it easy to find all the users for a specific game. It does not however make it easy to find all the games for a specific user. To allow that, you'll want to add an addition data structure that inverts the information.
So that'd look something like this:
player_games: {
"XDYNyN8il6TDsM4LuttwDzNuytj1": {
"-M5vf...U5zK": true
},
"NxH14...mxY2": {
"-M5vf...U5zK": true
}
}
Also see:
Firebase query if child of child contains a value
Firebase Query Double Nested
I recommend you also study the Firebase documentation on structuring your database, specifically the section on avoiding nested data. By mixing entity types as you currently do, you'll likely run into problems with security, and scalability.
The most idiomatic way to model your many-to-many relationship in the Firebase database is with four top-level lists:
players: {
$playerId: { ... }
}
games: {
$gameId: { ... }
}
player_games: {
$playerId: {
$gameId: true
}
}
game_players: {
$gameId: {
$playerId: true
}
}
Also see:
Many to Many relationship in Firebase
I am using the JSON API Spec along with the json-api-normalizer package. I'm running into a dilemma when it comes to normalizing single objects with included associations. For instance: I have a single restaurant that has many menus. The only time this becomes a hinderance is when the data is normalized and I need to retrieve the single restaurant that is now nested and can only be retrieved by knowing it's key, which in this case is it's id. This leads me to ask whether I'm normalizing my data in the wrong place. Right now I'm doing it in my reducer on successful retrieval:
case types.FETCH_RESTAURANT_SUCCESS:
return {
...state,
data: normalize(action.payload, { camelizeKeys: false }),
error: null, loading: false,
};
Where and what would be the best way to normalize my data so that I'm not essentially locked out of getting the things I need? Here is the output of the normalized state:
{
restaurant: {
data: {
restaurant: {
123: {...}
},
menus: {
345: {...},
678: {...}
}
}
}
}
IMO, this is only an issue when the data are getting really HUGE, otherwise you could normalize them in where you feel easy to maintain for your own favor. But if it's getting big, I think you need to design it with some lazy loading and consider with your business rules. Only render and normalize when needed.
When reading the redux docs I found this:
Still, you should do your best to keep the state serializable.
Don't put anything inside it that you can't easily turn into JSON.
So my question is, what's the benefit of keeping state serializable?
Or, what difficulties I may have if I put non-serializable data into store?
And I believe this is not unique to redux - Flux, even React local state suggest the same thing.
To make me clear here is an example. Suppose the store structure is like this.
{
books: {
1: { id: 1, name: "Book 1", author_id: 4 }
},
authors: {
4: { id: 4, name: "Author 4" }
}
}
This should all looks good. However when I try to access "the author of Book 1", I have to write code like this:
let book = store.getState().books[book_id];
let author = store.getState().authors[book.author_id];
Now, I'm going to define a class:
class Book {
getAuthor() {
return store.getState().authors[this.author_id];
}
}
And my store will be:
{
books: {
1: Book(id=1, name="Book 1")
},
...
}
So that I can get the author easily by using:
let author = store.getState().books[book_id].getAuthor();
The 2nd approach could make the "book" object aware of how to retrieve the author data, so the caller does not need to know the relation between books and authors. Then, why we are not using it, instead of keeping "plain object" in the store just as approach #1?
Any ideas are appreciated.
Directly from the redux FAQs:
Can I put functions, promises, or other non-serializable items in my store state?
It is highly recommended that you only put plain serializable objects, arrays, and primitives into your store. It's technically possible to insert non-serializable items into the store, but doing so can break the ability to persist and rehydrate the contents of a store, as well as interfere with time-travel debugging.
If you are okay with things like persistence and time-travel debugging potentially not working as intended, then you are totally welcome to put non-serializable items into your Redux store. Ultimately, it's your application, and how you implement it is up to you. As with many other things about Redux, just be sure you understand what tradeoffs are involved.
Further reading:
What is time travel debugging?
Adding to what #Timo said , If you want to setup relation between 2 states in your state tree and use computed values, reselect is the best suitable fit for that scenario. It allows to creareselectors which can be used to define computed states. In your case author can be created using a selector on top of book. https://github.com/reactjs/reselect
#timo 's answer is correct. In addition, I recommend a library called Redux-ORM to work with normalized/relational data in your Redux store. See my recent comment at Dealing with data consistency in a very large store in React + Redux SPA SaaS for links to more information.
Adding this because you asked for a suggestion. If you only want to create an object out of your class then you can simply create a function that returns an object. In your Book class it could be something like
function newBookObject({id, name}) {
return {id, name}
}
And your store would look like
{
books: {
1: newBookObject({id: 1, name: "Book 1"})
},
...
}
The object being returned can't contain any function's in it though, it should be just a plain static object with pure data and nothing else. You can't serialize something that isn't pure data.
Is there a way to configure a JsonRestStore to work with an existing web service that returns an array of objects which is not at the root-level of the JSON response?
My JSON response is currently similar to this:
{
message: "",
success: true,
data: [
{ name: "Bugs Bunny", id: 1 },
{ name: "Daffy Duck", id: 2 }
],
total: 2
}
I need to tell the JsonRestStore that it will find the rows under "data", but I can't see a way to do this from looking at the documentation. Schema seems like a possibility but I can't make sense of it through the docs (or what I find in Google).
My web services return data in a format expected by stores in Ext JS, but I can't refactor years worth of web services now (dealing with pagination via HTTP headers instead of query string values will probably be fun, too, but that's a problem for another day).
Thanks.
While it's only barely called out in the API docs, there is an internal method in dojox/data/JsonRestStore named _processResults that happens to be easily overridable for this purpose. It receives the data returned by the service and the original Deferred from the request, and is expected to return an object containing items and totalCount.
Based on your data above, something like this ought to work:
var CustomRestStore = declare(JsonRestStore, {
_processResults: function (results) {
return {
items: results.data,
totalCount: results.total
};
}
});
The idea with dojo/store is that reference stores are provided, but they are intended to be customized to match whatever data format you want. For example, https://github.com/sitepen/dojo-smore has a few additional stores (e.g. one that handles Csv data). These stores provide good examples for how to handle data that is offered under a different structure.
There's also the new dstore project, http://dstorejs.io/ , which is going to eventually replace dojo/store in Dojo 2, but works today against Dojo 1.x. This might be easier for creating a custom store to match your data structure.