I have a redux store like so:
{
'1f458697-e2c0-4d11-ada0-ee7b113c2429': {
name: 'Jim',
title: 'Developer',
active: true
},
'4498eb08-3786-495a-a66c-21a65138ab24': {
name: 'Darren',
title: 'Human Resources',
active: false
},
'c7975551-153f-4eab-a875-ed5445f76252': {
name: 'Francesa',
title: 'Chief of Internal Operations',
active: false
}
}
And I have a selector that gets an active user.
export const getActiveUser = (users) => _.find(users, { 'active': true });
My question is, whats the nicest way to include the ID of the user in the payload to use within my React component:
Is this is a bad practice and a sign that I should be using an array instead.
Should I just change my user payload to include the ID. This feels wrong as I would be duplicating data.
Should I manipulate that specific selector to include the users ID.
Yes, use arrays for table-like data and filter function for filtering the result set (if multiple users can be active at a time). If only one user can be active at a time, consider changing the db schema and create a separate variable activeUserId instead of having all of them contain unnecessary payload (and change the shape of the redux store accordingly).
- Is this is a bad practice and a sign that I should be using an array
instead.
Normalizing the data, so you can edit or delete items (users in your case) in O(1) is a good approach, which is also covered in the Dan Abramov's idiomatic redux course.
- Should I just change my user payload to include the ID. This feels wrong as I would be duplicating data.
Since you don't usually change IDs, adding them inside the user's object should not be a problem, and it should give you quick access to the ID. However, if you don't won't to duplicate that's acceptable as well.
- Should I manipulate that specific selector to include the users ID.
Part of the the selectors role is to create derived data, just like what you do when you filter the users. So if you want to the the ID to each user, this is a good place to do so. Don't mutate the objects, just create new user objects with ID. However, if you've got lots of users, you should use memoized selectors or add the ID as part of the payload to prevent performance issues.
Related
i just want to know this.whether state json object binding and normal json object binding is same or not? below is the example.
1st example
state = { name: "Default", email: "" };
binding data : this.state.name
this.setState({ name: e.currentTarget.value })
2nd example
const data= {name: "Default", email: ""}
binding data to control: data.name
onchange={e=>data.name=e.value}
both are working fine but want to know which one is better in performance?
my application dosent need any imutable data because i not displaying data dynamically i need to fetch the data from api on component load and posting the data to api on form submit. so i am using the 2nd approch. where i feel state will unnecessarly load render object.
so can any one suggest which one is better?
If the state is not associated with any UI component then changing it will not re-render anything so functionally both will work the same.
In terms of performance 2nd approach will be faster as it is a direct object manipulation whereas calling setState is a function call and doesn't guarantee immediate execution.
However do not use 2nd approach at all because it will create confusion for the next developer who manages such code(In my opinion). In the long run when the data grows you will have to keep a separate state obj for managing the data and the UI.
So it is always better to keep them separate from the beginning.
in a given app, lets say i have an array that hold 100,000+ object.
objects look like following
let collection = [{
name:'name',
price: 10,
group_id: 1
},
{
name:'name 2',
price: 8,
group_id: 2
},
];
now lets say i have a view which show all 100,000 object, and allow users to filter list by price range or group_id.
--given that such list can be a static list loaded from remote json, or a redux saved collection.
what is best method to filter this filters using price & group filters ?
my first thinking was to keep another array called "filtered_list" in the state of parent component, and when ever a filter change, the filtered_list will reconstruct by filtering parent Collection (looping 100,000+ object again).
but this look not so performant, so i consider may be i should write some logic that decied if the new filter should use the already filtered_list or use parent collection
example :- if group_filter was group_id = 1, then a price filter was added then i should filter only filtered_list, since all inputs of group_1 is already in filtered_list, otherwise if group_id changed from 1 -> 2, then i must refilter the whole big collection, because filtered_list doesnot contain group_id =2 items, its on collection only...
this bring me to another problem.. where should i maintain the filtered_list variable ?
if i added it to redux store, this violate princible of redux that store should only hold information needed to build data, and not calculated data.
const App = props =><div>
<aside>
<Filtes />
</aside>
<article>
{props.collection.map(item=><label>item.name</label>)}
</article>
</div>
export default connect( ({collection})=>({collection}) )(App)
I've been using the reselect library which is recommended in the Redux docs for computing derived data:
Reselect is a simple library for creating memoized, composable
selector functions. Reselect selectors can be used to efficiently
compute derived data from the Redux store.
http://redux.js.org/docs/recipes/ComputingDerivedData.html
So you could have a selector that looked something like this:
const getGroupdId= state => state.selectedGroupId
const getIteams = state => state.collection
const getVisibleItems= createSelector(
[getItems, getGroupId],
(items, groupId) =>
items.filter(i=> i.group_id === groupId)
)
Since the selector is memoized, it will only be recomputed when the selected groupId changes. I've also combined reselect with an ImmutableJS state in the past as well, which in my experience increased performance when querying large data structures.
I want to ask the community about an ideological problem.
Lets imagine todo-list on react/redux, you have single state where todoItems array is served. But now lets imagine I want to have few components on the page that are render todoItems with different UI. And I need to update each these components on CRUD of todoItems. What is your architectural approach of this issue? Don't forget we have a large database and we can get todoItems with pagination only.
Update:
Lets make it clear. When we implement redux life cycle with this UI we have 2 options:
1) Serve one array of todoItems into singleton redux state object.
Advantages: all our components will updates by object changing.
Problems: we can't get ALL data from our database, but have to show different paginated/filtered data, so we can't implement pagination/filtering on frontend-side. We have a few different components and the have to render different objects collection. So it doesn't fit.
2) We can use different keys into our global redux state.
Advantages: we can independently get data for each component
Problems: other components will not feel when object changing in one of them. In this case we have to write custom code.
I just want to know maybe I'm missing something and we have other option or maybe someone have good architectural approach to this problem.
I bet your complications come from the point of view which unfortunately quite common among redux community: trying to keep redux shape as close to UI shape as possible.
Try no to think about redux state as a substitute for the Component states. What redux should know about is actual todos only (id, title, date of creation, etc.). Let Component-specific data like pagination stuff live in Components state. When user goes to next page in one of the Components what should be updated is this Component state (pageNumber, from, to, amount, etc.). redux should be updated only in case necessary todos are missing.
The useful analogy is to thinking about your redux as good old SQL-database: redux store state is data itself, selectors and actions are queries and stored procedures, React Components are views with selected data.
Update: Ok, seems like what you are looking for is state normalization. Separate todos details from the lists of ids. This way updates of todo fields will be sensed by all the Components. On the other hand you'll be able to keep separate collections of todos in different Components. Namely make state look like this:
{
funnyTodos: [ 'id1', 'id2' ],
boringTodos: [ 'id3', 'id4' ],
recentlyDoneTodos: [ 'id1' ],
todos: {
id1: { name: .... },
id2: { name: .... },
id3: { name: .... },
id4: { name: .... },
}
}
Implementing pagination in this case is just a matter of getting list of todos ids for the next page from back-end and then loading missing todos for given ids.
I'm trying to follow the "Observable data store" pattern in Angular 2 (detailed in this blog post from Angular University) From what I understand, this means that, if I have a service called TodoStore, I would subscribe to TodoStore.items$ so I could get all the latest updates for my to-do list in real time (as other components add, remove, or edit Todos.
However, what if I have two components side-by-side that display different Todolists, filtered on the server-side? One might display Todos due today while another would show Todos due on a user-selected date.
In this case, I would not be able to use the same TodoStore, as both would be fetching different data from the server. How do I handle sharing this service between these two components? My urge is to go back to an angular1-style getToDoList() service method, but then I'm storing state inside a single component and can't possibly share data between multiple components without making extra API calls.
If your lists really have to be filtered server-side and you have an unknown number of simultaneously displayed lists and a new server-request has to me made for each list + filter, then it is perfectly possible that using a single observable (TodoStore.items$) might not be a viable solution here and maybe some kind of getTodoList(forFilter) might be easier/quicker to implement.
Remeber: There is no such thing as "The perfect solution for all cases."
However: Even in this case you could use a store, which could something like this:
interface ITodoListDictionary {
[key: string]: Todo[];
}
#Injectable()
export class TodoStore {
todoLists$: BehaviorSubject<ITodoListDictionary> = new BehaviorSubject<ITodoListDictionary>({});
getListByKey(key: string): Observable<Todo[]> {
return this.todoLists$
.pluck(key)
.distinctUntilChanged() // optional, so you only get the update if there is an actually new list
.share();
}
// this would be called whenever the rest-response for a given list arrives
setListByKey(key: string, list: Todo[]): void {
this.todoLists$.take(1)
.do(dict => {
const newDict = Object.assign({}, dict, {[key]: list});
// if you are using TS2.1 you could also use:
// const newDict = {...dict, {[key]: list}};
this.todoLists$.next(newDict);
})
.subscribe();
}
}
...and in your template you could use it like this
<todo *ngFor="let todo of todoStore.getListByKey(someKey) | async" todo="todo"></todo>
Please keep in mind that is just one possible solution out of many - without seeing your actual application-flow it is hard to tell which might be the best solition.
I'm using React with Redux as my store. I'm also using the react-redux library to integrate the two. My store contains two sets of data:
Task { id, name, assigneeId }
User { id, name }
I have a TaskListComponent which (using react-redux) connect-s to my store using:
#connect(state => {
tasks: state.tasks,
users: state.users
})
I need both because the list has a filter allowing for searching my task name or user name - my component needs to be 'user aware'.
This component lists out another component called TaskItemComponent which displays the task name and the name of the assigned user.
I'm struggling to decide on the best approach for resolving a task's assigned user.
React guidelines tell me that the Item component should take a Task as a prop, and resolve the User itself in the render function. However, this requires the component to be store-aware and, using the react-redux library, it doesn't appear to be designed to allow a component to access the store without being connect-ed to it.
Or I could resolve the User in the list and pass it to the Item component along with the task, e.g. <TaskItemComponent task={task} assignee={resolveTaskAssignee(task)} />. This has the benefit of keeping my Item 'dumb', and means I don't need to have it listening to store changes (or even know about the store).
Any advice would be appreciated.
Both approaches are fine. I'd start with passing props from outside, and once it gets tedious, let the Task component receive task as a prop but read its user by using connect.
See also https://stackoverflow.com/a/25701169/458193.
There's nothing inherently wrong with option #2. You have to do data ops somewhere. It will always be the right place to do those ops in the smart component.
Personally, I'd prefer a better data model in the store. But, you got what you got.