Handling collection changes in React - javascript

We're rolling out our own mutable collection class to use within a React list component. Since the actual contents to be rendered are managed separately by that collection (which we inject in the component via props), we're faced with two design doubts:
whether the collection object should be held in the state or, instead, kept in the props or an instance property of the component (given it can handle its own state);
what a good idiom for triggering rendering on collection changes would be.
We've been brainstorming the best way to do this. Currently the collection's mutation methods return a promise which resolves with the collection itself; if we keep the collection in state, is it a good idea to done() the promise with something like (in CoffeeScript)?
#state.collection_object.add_an_item('foo').done(
(mutated_collection_object) => #setState(collection_object: mutated_collection_object)
)
I'd like to get some insight on which approaches to this you've taken/seen so far.

Holding a collection in the state can get messy pretty quickly, with props I feel it's even worse. Have you considered the holding the collection outside the component entirely? I've gone that route.
You can trigger synthetic events upon change with something like Node's EventEmitter, then listen for changes from within the component in order to trigger the re-render. Plus you can move code out of the component that more specifically deals with the collection itself.
I found this simple example, hopefully it's of some help. Good luck!
http://mwdesilva.com/posts/event-driven-react-js-components-via-an-event-emitter-mixin

Related

What's the reason for not getting the variable I'm expecting in the functional component?

I'm familiar with useState hook for storing variables that change and need to reload the component. Are variables not local to each function call? For example, I have a functional component that I passed ticket information to. I take that information store it in a variable and pass it to another screen. That component is render in a flat list depending on which one is called I want to store that value and pass it to another screen. My problem is, that value is getting stored in the local object but only the value of the last item rendered not the one pressed. Here is my code:
If I save ticket from params, update it with the "siteCode", and pass it in the params of the onPress event, I don't get the results i'm looking for. If i pass siteCode outside of the custom object I get the results I'm looking for. I just want to understand what I'm missing here. Do i still need to use the useState hook even though i'm not looking to render the component again? Thanks
You are breaking the contract, so unfortunately you get whatever you get. And since it's not a supported use case you sadly can't expect it not to change in different React versions either.
React expects a pure functional component to be, well, a pure, functional, component (referentially transparent, no side effects). You are mutating your props, which as I said is not supported (this seems to come up a lot on github issues on the React repo).
In ye olden days, if your component was not pure you used a class. Now we have hooks, but the hook is essentially a clever workaround: because React knows about the hooks you don't violate the functional component contract. But that doesn't mean anything goes, if you have a side effect (like mutating an object defined elsewhere) then you need to put it in a hook or screwy things will happen.
N.B. even in a class, or even outside of React entirely, it's rarely (never?) a good idea to mutate the parameter to a function unless that mutation is the only thing the function does.

Why use setState in React?

If I have a class with a bunch of properties, it seems like a hassle to put the properties that I modify inside (for example) this.state.myProp1 instead of this.myProp1. and then I need to make a copy of whatever property it is before I send it off to setState (because I can't mutate it directly). Like an array of objects for example.
At some point I display some of these properties so that means that I need to hold all my class properties inside this state, and then keep track of what I need to refresh, instead of refreshing the whole thing.
I almost prefer to use this.forceUpdate() instead and have my render() refer to class properties directly. Why does react "make" people use this.state and setState. Is it for performance reasons?
setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state. This is the primary method you use to update the user interface in response to event handlers and server responses.
So basically setState is there to tell react when to re-render. Also setState behaves asynchronously, and updates the state only when necessary. So if you call setState multiple times immediately it will update only on the last one so as to minimize the number of re-renders and be less taxing on the browser. If there was no setState and react re-rendered every time the data changed, the browser experience would be terrible.
You don't have to use React this.state and setState if you don't want to. You can always use redux or mobx to manage the state.
Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made.
And yeah, that's why you've to make a copy of whatever property it is before I send it off to setState
IMHO, component state is an elegant concept for some special case. for example when you want to monitor the content change of a text input on live, that is, not after hit save or submit button. under such situation, a component state would be ideal place to store the temporary input and you will not get overhead to use redux action to respond on the every incomplete input. it is just like a buffer to provide performance improvement.
1. Reasons behind setState
The main reason for having to use setState is its asynchronous execution, from the react docs:
React intentionally “waits” until all components call setState() in their event handlers before starting to re-render. This boosts performance by avoiding unnecessary re-renders.
If the state object was updated synchronously it would cause consistency issues, since props are not updated until the parent component is re-rendered, so, mutating this.state directly would lead to inconsistency between props and state.
For further reference, you can check this this Github thread.
2. Reasons behind this.state
The main advantage of the state object is its immutability which couldn't be accomplished with component properties, also there is the separation of responsibility between props and state, which is way easier to handle and update individually.
Why does react "make" people use this.state and setState. Is it for performance reasons?
That's a good question - the existing answer from J. Pichardo is quite correct but I wanted to address the why in a little more depth - as opposed to what or how.
Really a better question is - why does React exist? According to this article
React’s one-way data flow makes things much simpler, more predictable, and less bug-prone. One way data flow greatly simplifies your thinking about state because no view can ever mutate the state directly. Views can only send actions up to the global state store.
Really theres a whole bunch of reasons why React has it's place as a useful UI library. But in regards to your question - uni-directional data flow - this is the main reason.
relational UIs get complex. When an app has to consume, display and update even just a modest amount of relational data and have that information displayed across multiple elements, things can get messy fast.
Using state and props the way that React does allows one to differentiate and guarantee whether a piece of the UI will just receive data to display or whether it might change it too.
If you store that data just in a random key you have no real way of knowing whether the value is changed and what changed it. By separating out your state from your component in this way, it decouples the data from the element and makes it much easier to share data between elements and also change that data in different ways.
according to this article on coupled object interfaces a tightly coupled entity is bad because:
A tightly Coupled Object is an object that needs to know about other objects and are usually highly dependent on each other's interfaces. When we change one object in a tightly coupled application often it requires changes to a number of other objects. There is no problem in a small application we can easily identify the change. But in the case of a large applications these inter-dependencies are not always known by every consumer or other developers or there is many chance of future changes.
This very much is applicable in UI development also. In my opinion this is why not setting state is going to cause you some pain later on.

Flux: should not-top-level views be "dump" (do not fetch data from stores)

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.

How to pass a prop to every component in react.js?

I'm setting up a site using react.js. the client receives a massive json through ajax that is then used to populate all the necessary fields, graphs, etc. Seeing as this json will cover pretty much all the information contained on the site, it has be accesible in almost every single component. Is there a clean way to pass it to every last component (and there are a lot of them)? Passing it the regular way to ~70 components seems dirty and inefficient.
As React's documentation states, you could have components communicate by integrate a global event system, and then subscribe to an application-data event from all your components, in componentDidMount().
This way, each time you will emit the application-data event from within the code responsible for pulling the website data, all components will receive that data. At that point, you can call setState().
Please be careful and unbind the events once a component goes "out of scope", inside componentWillUnmount().
Failing to do so will result in memory leaks, as you will have the event handler dangling, and it will be called each time you pull the website data, even if your Component's instance has been removed from the DOM.
You could also try to make your components pull data by themselves, as sending a huge JSON around, is not the best solution. I mean, each component should use the data it needs, in order to work, not the whole website data. The way I would alter this would be by parsing the JSON object and storing it for reference in a variable, on a scope that is accessible to all components, and use the event system to only notify the components that the data is ready, and each component would go to the global data object and get their data.
Example(pseudo-code):
XHR.getData
XHR.onReadyState => GlobalNameSpace.data = data
EventSystem.PUBLISH('application-data')
// component code
Component {
EventSystem.SUBSCRIBE('application-data') =>
dataNeededForInit = GlobalNameSpace.data.componentXData
}
Reference: https://facebook.github.io/react/tips/communicate-between-components.html
Context might fit the bill. It might not be particularly tidy solution but perhaps that would be a starting point for you.

ReactJs: How to pass the initial state while rendering a component?

I know I can pass props while rendering a component. I'm also aware of the getInitialState method. But the problem is, getInitialState isn't quite helping because my component doesn't know it's initial state. I do. So I want to pass it while I'm rendering it.
Something like this (pseudo-code):
React.render(<Component initialState={...} />);
I know I could use a prop to work as the initial state but this smells like an anti-pattern.
What should I do?
EDIT FOR CLARITY
Imagine I have a CommentList component. By the time I first render it, the initial state corresponds to the snapshot of current comments from my database. As the user includes comments, this list will change, and that's why it should be a state and not props. Now, in order to render the initial snapshot of comments I should pass it to the CommentsList component, because it has no way to know it. My confusion is that the only way I see to pass this information is through a props which seems to be an anti-pattern.
Disclaimer: Newer versions of React handle this on a different way.
Only permanent components might be able to use props in the getInitialState. Props in getInitialState is an anti-pattern if synchronization is your goal. getInitialState is only called when the component is first created so it may raise some bugs because the source of truth is not unique. Check this answer.
Quoting documentation:
Using props, passed down from parent, to generate state in
getInitialState often leads to duplication of "source of truth", i.e.
where the real data is. Whenever possible, compute values on-the-fly
to ensure that they don't get out of sync later on and cause
maintenance trouble
You can still do:
getInitialState: function() {
return {foo: this.props.foo}
}
As they will be the default props for your app. But as long as you are using a prop to set a value that presumably won't change, you can use the same prop inside of the render function.
<span>{this.props.foo}</span>
This props won't be modified, so no problem using it each time the render is called.
Edited answer:
In this case your initial state should not be a prop, should be an ajax call which populates the comment list.
To quote the React docs:
Using props, passed down from parent, to generate state in getInitialState often leads to duplication of "source of truth", i.e. where the real data is. Whenever possible, compute values on-the-fly to ensure that they don't get out of sync later on and cause maintenance trouble
And:
However, it's not an anti-pattern if you make it clear that synchronization's not the goal here
So if your props include a value and an initialValue, then it's clear that the latter is for initialization, and there's no confusion.
See the React docs for code examples.
If you know the state then I would tend to argue that the component you are rendering is not really in control of it. The idea in React is that any particular piece of state lives in only a single location.
After seeing the other answers, and studying a little bit about it, I've come to this conclusion:
If you are rendering React in the client (compiled or not), which is the default approach, you should try to make an extra Ajax call from inside your component to get the initial state. That is, don't use props. It's cleaner and less error prone.
However, if you are rendering in the server (Node.js or ReactJs.NET), there's no reason to make this extra Ajax call for each request.. Besides, it's not SEO friendly. You want the complete page to come as the result of your request (including data). So, as #RandyMorris pointed out, in this case it's ok to use props as the initial state, as long as it's exclusively the initial state. That is, no synchronization.

Categories

Resources