React-Redux mapStateToProps with dynamic (uid based) path - reactjs

I am new to React and React-Redux. I'm trying to pass "mapStateToProps" using a dynamic pathway depending on the users id. The basic code being used follows:
const mapStateToProps = (state) => {
console.log(state);
console.log(state.firebase.auth.uid); <===== THIS DISPLAYS THE USERS ID, PROVING THE PATH EXISTS
return {
courses: `state.firestore.ordered.${state.firebase.auth.uid}`, <======= THIS LINE IS AN ERROR EVEN THOUGH THE PATH EXISTS
}
}
The code works fine if I manually type in the users ID. Lets say the users ID is "12345", then replacing that line with
courses: state.firestore.ordered.12345, <======= THIS LINE WOULD WORK
Any clarification as to why this doesn't work and an alternative method of making this work would be greatly appreciated!

If you want to access dynamic property in JS object, you need to use square braces
courses: state.firestore.ordered[state.firebase.auth.uid]

Related

Cannot return documents based off a sorted index using Fauna DB

I'm bumbling my way through adding a back-end to my site and have decided to get acquainted with graphQL. I may be structuring things totally the wrong way, however from following some tutorials I have a React front-end (hosted on Vercel), so I have created an api folder in my app to make use of Vercel's serverless functions. I'm using Apollo server and I decided to go with Fauna as my database.
I've successfully been able to return an entire collection via my API. Now I wish to be able to return the collection sorted by my id field.
To do this I created an index which looks like this:
{
name: "sort_by_id",
unique: false,
serialized: true,
source: "my_first_collection",
values: [
{
field: ["data", "id"]
},
{
field: ["ref"]
}
]
}
I then was able to call this via my api and get back and array, which simply contained the ID + ref, rather than the associated documents. I also could only console log it, I assume because the resolver was expecting to be passed an array of objects with the same fields as my typedefs. I understand I need to use the ref in order to look up the documents, and here is where I'm stuck. An index record looks as follows:
[1, Ref(Collection("my_first_collection"), "352434683448919125")]
In my resolvers.js script, I am attempting to receive the documents of my sorted index list. I've tried this:
async users() {
const response = await client.query(
q.Map(
q.Paginate(
q.Match(
q.Index('sort_by_id')
)
),
q.Lambda((ref) => q.Get(ref))
)
)
const res = response.data.map(item => item.data);
return [... res]
}
I'm unsure if the problem is with how I've structured my index, or if it is with my code, I'd appreciate any advice.
It looks like you also asked this question on the Fauna discourse forums and got an answer there: https://forums.fauna.com/t/unable-to-return-a-list-of-documents-via-an-index/3511/2
Your index returns a tuple (just an array in Javascript) of the data.id field and the ref. You confirmed that with your example result
[
/* data.id */ 1,
/* ref */ Ref(Collection("my_first_collection"), "352434683448919125")
]
When you map over those results, you need to Get the Ref. Your query uses q.Lambda((ref) => q.Get(ref)) which passes the whole tuple to Get
Instead, use:
q.Lambda(["id", "ref"], q.Get(q.Var("ref")))
// or with JS arrow function
q.Lambda((id, ref) => q.Get(ref))
or this will work, too
q.Lambda("index_entry", q.Get(q.Select(1, q.Var("index_entry"))))
// or with JS arrow function
q.Lambda((index_entry) => q.Get(q.Select(1, index_entry)))
The point is, only pass the Ref to the Get function.

looking for query

Im trying to find me based on city.(not using lat and long).
i have following function but as a newbie to gremlin im not sure is a right approach or not.
async function addRestfgaurant(restaur) {
// to add restaurants
after adding restaurant will do the same while adding Person with edlivesIn then will try to query restaurants near me. (im trying to make dining by friend api)
i want to Know is it right approach or not? or if someone has example of this type of query it would be really helpful.
What you are doing is reasonable but you can simplify things a bit. By using as steps to label earlier parts of the query you can then refer to them in the from and to parts. Note that in my example I also changed it to be all one query rather than three.
async function addRestaurant(restaurant:InputRestaurant) {
// to add restaurants
await g.addV("Restaurant").as('r').
property("restaurantId", restaurant.restaurantId).
property("name", restaurant.name).
property("city", restaurant.city).
property("street", restaurant.street).next()
// to add city
.addV("city").property("cityName", restaurant.city).as('c').
//edge
.addE("withIn")
.from_('r')
.to('c')).next()
return {
name: restaurant.name,
restaurantId: restaurant.restaurantId,
city: restaurant.city,
street: restaurant.street,
}

React-Redux state not updating as expected—am I mutating reducer arguments?

thanks in advance for your attention with this (I believe) very basic question. I'm working on building my first "full-stack" application, and am running into something I can't quite wrap my head around with React-Redux. A brief explanation of the project: users can submit band idea names, and up or down vote others' submissions. Now, I believe that my problem is I'm not interacting with the state appropriately in my reducer dealing with MODIFY_BAND_SCORE actions. Here's the git repository, and I'll also copy and paste my store reducers here:
export const store = createStore(
combineReducers({
bands(bands = defaultState.bands, action) {
switch (action.type) {
case mutations.CREATE_BAND:
return [
...bands,
{
id: action.id,
owner: action.owner,
name: action.name,
score: 0,
flags: 0,
},
];
case mutations.MODIFY_BAND_SCORE:
let targetBandIndex = bands.findIndex(
(band) => band.id === action.bandID
);
let targetBand = bands.splice(targetBandIndex, 1)[0];
targetBand.score = targetBand.score + action.value;
bands.splice(targetBandIndex, 0, targetBand);
return bands;
}
return bands;
},
users(users = defaultState.users, action) {
return users;
},
}),
applyMiddleware(createLogger(), sagaMiddleware)
);
Hopefully that's enough context to make informed suggestions about what's going on here—my apologies for not having a truly minimal working example for this! The behavior I'm seeing from Redux-Logger when I dispatch an action of type MODIFY_BAND_SCORE is that I am (in a way) seeing the change reflected in that the correct band is having its score modified by the correct amount, but it is showing somehow in the previous and next states! Here's a screenshot:
I feel like I've maybe made this post longer than what it needs to be, am I correct in thinking that in my case for mutations.MODIFY_BAND_SCORE I'm actually modifying the state directly? This is probably occurring with my calling of .splice() on bands isn't it?
Like Siddharth mentioned,
let copyOfBands = [...bands]
will create a copy for you. It's important to remember that one of the key parts of Redux is that the store is read-only. It can be easy to forget that when dealing with non-primitive data (I've certainly done that a bunch), but you should always try to remember to make copies of the data, modify the copy, and then push the copy to store. This helps prevent you from getting really weird and hard to debug errors.
It is important to remember that the spread operator here will creates a shallow copy of the array, which means if you have other non-primitive objects inside the array (such as other arrays), you will have to copy those as well.

Redux selector on many to many

React + Redux recommend saving data normalized and using selectors to get derived data. So in our store we save Users and Tags which have a many to many relationship.
type Store = {
entities: {
users: User[];
tags: Tag[];
userTagMapping: { userId: string, tagId: string }[]
}
}
And in our view we want to show some derived data for this many to many relation-ship. For example we want to calculate the total users with some tag or the online-users with some tag. Right now we solved this using rselect. The only problem is that calculating these things becomes quite tedious. For example we have a selector which returns a map from a tag-id to a list of users to show which users belong to this tag (and vice versa a selector from user-id to tag list).
const selectUsersPerTag = createSelector(
selectUsers, selectTags, selectUserTagMapping,
(users, tags, mapping) => {
let result = {};
for (const tag on tags) {
const isUserMappedToTag = user => ({userId, tagId}) => userId == user.id && tagId === tag.id
result[tag.id] = users.filter(user => mapping.some(isUserMappedToTag(user)))
}
return result
}
)
and in my opinion this looks quite ugly and is a bit too hard to read for my taste.
My questions are:
Are we understanding the recommendations correctly (to use normalization and selectors)?
Is using a map the correct way to process our data and show it in the view or is there a better way? I am asking because this basically copies our data (slightly modified) many times into the props of our React components
Is there a nicer way to do this mapping (which is basically a SQL like join)? Because I really don't like this imperative approach and would find a functional one much nicer.

Structure: How to represent a search input, search query, and search results using mobx-state-tree?

I've got an app using mobx-state-tree that currently has a few simple stores:
Article represents an article, either sourced through a 3rd party API or written in-house
ArticleStore holds references to articles: { articles: {}, isLoading: bool }
Simple scenario
This setup works well for simple use-cases, such as fetching articles based on ID. E.g.
User navigates to /article/{articleUri}
articleStoreInstance.fetch([articleUri]) returns the article in question
The ID is picked up in render function, and is rendered using articleStoreInstance.articles.get(articleUri)
Complex scenario
For a more complex scenario, if I wanted to fetch a set of articles based on a complex query, e.g. { offset: 100, limit: 100, freeTextQuery: 'Trump' }, should I then:
Have a global SearchResult store that simply links to the articles that the user has searched for
Instantiate a one-time SearchResult store that I pass around for as long as I need it?
Keep queries and general UI state out of stores altogether?
I should add that I'd like to keep articles in the stores between page-loads to avoid re-fetching the same content over and over.
Is there a somewhat standardized way of addressing this problem? Any examples to look at?
What you need might be a Search store which keeps track of following information:
Query params (offset, limit, etc.)
Query results (results of the last search)
(Optional) Query state (isLoading)
Then to avoid storing articles in 2 places, the query results should not use Article model, but reference to Article model. Anytime you query, the actual result will be saved in existing store ArticleStore, and Search only holds references:
import { types, getParent, flow } from 'mobx-state-tree'
const Search = types.model({
params: // your own params info
results: types.array(types.reference(Article))
}).views(self => ({
get parent() {
return getParent(self) // get root node to visit ArticleStore
}
})).actions(self => ({
search: flow(function*(params) {
this.params = params // save query params
const result = yield searchByQuery(query) // your query here
this.parent.articleStore.saveArticles(result) // save result to ArticleStore
this.results = getArticleIds(result) // extract ids here for references
})
}))
Hope it's what you are looking for.

Resources