So im working on a React "Todo" list as a first React project, im using Rails as an API backend (strictly taking in and sending back .json), I am fairly familiar with Rails or at least the basics.
Currently I have a few Components for handling the actual "List". This being a ListContainer parent component (Holds the state for "Lists" which is an array of Lists) as well as all the Add/Update/Delete/Index(Set Lists initial state) functions.
Along with some child components (ListForm and List), both pretty self explanatory. List being a dumb component just holding the List title and description, and ListForm being the actual form to submit a new list.
I am using axios, and so far Create/Index/Update/Delete are working great for Lists. However I am running into the issue of being unsure how to handle the list items themselves. Currently in the rails side Lists has_many list_items and list_items belong_tolist`.
So rails has the relationship side all buttoned up...but im really unsure how to handle the actual items on the javascript side (for each list).
My first initial guess was to switch "List" dumb component to a smart component that handles state, in this state would be an array of "list_items" that belong to that particular list. When the List is loaded I imagine axios performing a GET request for that lists items within the component. And then basically handling add/delete/update similar to how the ListContainer component handles it for Lists (but instead making "List" component the de-facto container component for ListItems (which is currently a "dumb component")
Does this make sense? I honestly am still pretty new to react so handling relationships on the front end side is something im not familiar with yet. But storing state within a child that "belongs_to" a parent state/component makes the most sense initially? Unless I am overthinking it?
I think your proposed solution makes sense. Following your pattern you would probably have another Component, ListItem, and you would map through the listItems state in List and display a ListItem for each item.
That being said, many people learning react have a tendency to over-complicate it by having too many components/different files interacting. At one time the React community encouraged this, but they have since backed off on doing so. Many people now consider having presentational components (or "dumb" components, as you call them) an antipattern. See, for example, this note from Dan Abramov enter link description here
Related
I'll mention in advanced that this is not a technical question on how to do the data update between 2 sibling components, rather what is the correct way to do so.
I have the following component tree structure:
App
|
-- Home
|
-- SearchBar
| |
| -- Filters
|
-- ItemsList
ItemsList has logic in it to load the list of items from an API call and show the list of items on the page. It also manages the state of the articles. If an article is deleted it removes it from the list and updates it's state.
SearchBar is a component that contains a textual search that is displayed above the list where a user can enter text to search and also has a button that opens the Filters component where the user can filter different parameters. Once the user search's or filters the list in the ItemsList component should be updated accordingly.
There are a few ways I can think to achieve this:
Using react context - The provider will be on the Home component (or another component for holding SearchBar and ItemsList - and both SearchBar and ItemsList will contain a consumer that will updated the state with a method in the provider - those updating the components. This in my opinion create some dependency between those components and they are not really standing on their own (the ItemsList component should be used in other pages as well - of course this is still possible, but yet does not feel so "clean").
The ItemsList component will contain public methods such as "delete item", and "clear list" and those methods will be called from the home component. The SearchBar will get a property with a function as an event - something like "onFilterChanged" and will call the method on ItemsList (I will need to hold a ref to that component). But working like that feels like each component can stand and be re-used on it's own merit - but loosing the "reactiveness" and more wire up that needs to be done.
Are there any other ways to achieve what I'm looking for that I'm not thinking of?
What is the correct way to architect this kind of solutions?
When two siblings need access to the same state, keeping the state in a mutual parent component is a common and recommended way of handling it (the official React documentation encourages that approach for most cases). That way, both the state and any methods to update the state can be passed to both children as needed, and any updates made by one child will be reflected in the other child.
There can be drawbacks to that approach: Depending on the size of the application, prop drilling can make code confusing and difficult to maintain—especially if one component that is using said data is being used in multiple places, deeply nested, or both.
For such occasions, holding the state in context or redux is a more appropriate approach. The first option that you listed is completely legitimate and what I would recommend. Maybe extracting your context entirely (not keeping it in your Home component and instead creating the context in its own file) would help things feel more "clean."
Determining when to use which approach is something that comes with time and experience. When choosing an approach, it is helpful to keep your future plans in mind. If you know the application will be small and simple, keeping the state in a parent component is a great move. If you have big plans for your application, using context or Redux from the start will be easiest.
Thankfully, the worst case scenario is that you decide to change from one approach to the other, which can always be done (confusing and tedious as it may be at times).
I'm constructing a React App that is basically a photo sharing app.
Here's some use cases:
User can upload photos and videos
User can see the photos in a list view
User can reorder the photos in the list
User can select photos from list and performs actions based on their selection
Users can attribute properties to these photos, such as message, title, etc. Lets call an image + its properties a Post
Here's some major architectural components:
A CDN service to upload, host, and transform image and video creation
A backend application paired with a DB for persistent storage
I'm looking for a good way to organize all this data in state. One thought I had was to break up the state into separate, simple data structures.
Roughly this:
posts <Array> maps Post index to Post ID
media <Object> maps Post ID to Image Urls
selectedPosts <Object> maps Post ID to Boolean
loadingPosts <Object> maps Post ID to Boolean
So here we have four data structures.
posts: Determines what posts are in state and in what order
media: Attributes Post IDs to Image URLs
selectedPosts: Determines what posts are selected
loadingPosts: Determines if a given post is loading or not
I'm surfacing these via four React Contexts
Breaking up state into separate contexts makes it really easy for dependent components to subscribe to exactly the state they need. For example:
import React from 'react'
import useMedia from '/hooks/media'
export default ({ postId }) => {
const { media } = useMedia() // useMedia uses useContext under the hood
const imageForThisPost = media[postId]
return (
<Image src={imageForThisPost}/>
)
}
What I really like about this is that this component gets exactly the state it needs from global state and really only has one reason to re-render (pretend i'm using useMemo or something). I've worked with some tough React Redux web apps in the past where every component re-rendered on any state change because all the state was in one data structure (albeit memoized selectors could have fixed this).
Problems arise when it comes to use cases that impact multiple contexts. Take uploading an image as an example:
The sequence of events to upload a photo looks like this:
An empty post with ID, "ABC", is selected. Update selectedPosts context
User uploads a file and we wait for CDN to return image url
Update loading context of post ABC (loading == true)
(receives image url)
Update posts context at ABC
Update media context at ABC
Update loading context of post ABC (loading == false)
Deselect post ABC. Update selectedPosts context
Long, intricate, async sequences like this are tough to deal with, encapsulate, reuse, and test.
What's a better way to organize state for medium sized web applications like this with potentially long sequences of async actions and somewhat complex state?
Wishlist:
Easy to control re-renders
Easy to add extend/change app functionality (not a fan of huge deeply nested data structures)
Easy to test
Does not use Redux (but useReducer is fine) (I just don't like the huge overhead that comes with redux)
Anyone have any thoughts?
I know one way might be to emulate Redux using useReducer, actions, and selectors. And thankfully dispatch is a stable function identity in React. Idk, I just really don't like dealing with big, deeply nested objects. When product requirements change, those are such a pain to deal with because the entire application depends on a particular schema shape.
Old post, but am assuming that selectedPosts and loadingPosts are filtered posts objects.
Personally I would probably not have them as separate, but filter of posts which are marked loading / selected and upload those in code via some action?
I.e. state has list of posts, with loading / selected props and code does the filter on posts to upload - are you over complicating it? Presuming with some lookup one to many / many to many? on state for media to create the association? What did you end up doing? I would be using useReducer and dispatching updates to state, not sure context is needed unless its deeply nested.
I'm quite new to React, and I'm making a single page application with React.
So far, I've build the application with components and child components, having their own local state, however the child components doesn't really interact with one another, which is what I want them to, basically, with the least amount of boiler plate code...
The problem I'm facing, is that a change in some child component, should be able to update the state of another child component, somewhere else in the component tree.
A selection in one child component should also be able to trigger a function in another component updating it with data and so on.
I've considered having just one global application state, that all components can call and update when something in them changes, and this one application state will then update other components in the tree. Kinda like having a single "controller" with it's own state, that all components "views" can call, and which updates the states of other components as needed. (I'm used to WPF and MVC style of GUI programming).
What I've considered:
One could try to implement this with callback functions defined in the top of the hierarchy, to be sent down through the hierarchy and called from a child component when it changes.
This method however results in a LOT of boilerplate code that just passes functions to their child components. It feels wrong and hard to maintain...
To avoid all this passing around and boilerplate code, I've tried using a React Context, however this is not working as well as I hoped. I can only access the context from within the render function and from lifecycle functions, and sadly I often get complicated errors that are hard to understand. It seems like I'm exploiting React Context to do something you shouldn't use it for...
I've considered using a singleton pattern in JavaScript, however then that singleton needs to have a reference to the root component, and query for the component it needs to change... This seems like kind of a hack, and may not be that pretty, but idk.
I'm considering trying out React Redux however it seems to work in many ways similar to React Context (I'll be honest, I haven't read much into it yet).
What I need:
I need to ask someone with greater React experience than me: How do you keep a global application state, and update child components based on changes to the global application state? Also: Am I thinking about this all wrong? Am I trying to do something in a non-react way, failing to see how I should do it in React?
You can happily go with Redux or MobX, they're fine.
I suggest Taming The State from Robin Wieruch: https://roadtoreact.com/course-details?courseId=TAMING_THE_STATE
There are the book and the course. He shows different ways of handling React state.
Redux was created specifically for the problem yo stated.
Reacts follows a top-down down-top unidirectional flow in essence. Context API is useful in simple use cases but would fail horribly in a large scale application where you'd be creating consumers everywhere.
I'd suggest investing some time in Redux so that will save your precious time in long run.
There's a reason all big three frameworks require a state management library to be useful for large scale complex apps. (Angular has NgRx and Vue has Vuex).
TL;DR
Embers components are just smart HTML-Templates. Why they don't fetch their data for themselves like Angular? And how I can share route models over more URLs/pages. It seems that I have to know wich components are placed on which URL and I have to make them the data available over the route models. Why is this part not in the component?
I learn at the moment Ember.js. I try at least.
At the moment I have a strong problem to understand why Ember.js acts like it does. Please correct me if I am wrong at some statements. I am an Ember.js beginner. So maybe its not right what I point out here.
Lets say we have a Request on / then Ember tries to find a route model in app/routes/index.js this file contains the code which data I want to fetch from the backend. Next Ember will render app/templates/index.hbs in this file I have a component called car-list.
As far no problems but let us have a closer look. For me it feels very weird that I have to fetch at first the data by myself, why the component doesn't do this on its own? Next problem is then how can I share the model fetch logic between more routes? Maybe I want to place my component on many URLs/pages/routes then I have to copy the route model logic?
In my opinion, the component should fetch the data by itself, that you can easily insert the component on other pages without copy the whole route model fetch logic.
So I have to know wich components are placed on which URL and I have to make them the data available over the route models. Why is this part not in the component?
So maybe I am just not good enough with Ember and I just overlook something?
Components are very flexible. Components have made to be reusable. For example you can create a table component and use for cars, ships, etc.
So for reusability it's better you separate model providing from component.
But if you want to make a component which is for current project and need to fetch its data itself, you can fetch data in the component.
In some scenarios you might want to fetch data in routes. For example in your page you have multiple components and every component needs a projection of data model which fetched in route.
So it depends on your requirements, maybe you need to fetch data in component or in route or even both (mixed)
Components certainly can load their own data, and in many cases that is appropriate. But allowing the route to load the data has several important benefits that you get "for free" if you stick to that pattern:
your application's URL will always reflect the state of the data. You don't have to remember to synchronize it (in both directions -- changes to URL should change the data, and changing the data should change the URL).
you can write your templates knowing that they won't render until the data is present, allowing Ember to handle the asynchrony for you. This results in cleaner, simpler templates.
you get Ember's built-in error handling for when the data fails to load.
A username component that appears on many pages typically belongs fairly high in the route hierarchy anyway, like in the application template, where it's easy to load & render it once from a single place and have it remain visible on every child route.
But if you do need to use a component in many places and its data should be self-contained, it's fine to let it do its own loading. In that case you can either rely on Ember Data's store to give you cached responses (so you only trigger a network request the first time) or write a Service that handles some persistent state for your component.
Maybe at official flux website I saw a video were mentor said something like:
Only top-level React views should know about stores. All not top level
views should be dump and receive all information as properties.
Question: Is that right? Your argumentation, please
BUT, suppose you have some small React view Button.react that's reused on multiple pages. And suppose Button.react must know about some store data. If we won't fetch all data directly from the Button.react, we get a duplication of code at each top-level component which reuse Button.react. Is that ok for you?
I hope I am understanding your question.
One of the characteristics of React is its one-way data flow. Each component can be used by another component, just like one function can call another function. Just like a function, a React component should typically be able to get all the info it needs to do work (render itself) from the arguments passed into it. This is the function of props in React. When using Flux, sometimes the React Components, which are typically near the top of the view hierarchy, that actually fetch the data from the stores to pass down thru the application are called Controller-Views.
It is not an enforceable rule that every component doesn't become a Controller-View, getting its own state directly from a store, but it is a general practice for good reason. consider the two functions:
function renderToggleButton( isSelected ){
//... render the button
}
vs
function renderToggleButton(){
var isSelected = StateStore.getButtonSelectedState( id );
//... render the button
}
I think you will agree that the second function is more complicated and difficult to test. It has to know from where it is getting it's initial conditions. It also has to know how to identify itself in the context of the application. These are two things the function should not have to know.
Now imagine an application full of functions like this. If one function is misbehaving, it becomes very difficult to trace its inputs; to test it under controlled conditions. I hope that clarifies the guidance given for passing data thru the application as props.