state vs props for scenario with separate view and data model - reactjs

I'm building an application where I would like to provide separate views for same data.
In my current implementation, data is obtained by web service call and persisted in state of App component in App.js. App component hosts (renders) another component called StackEditor, which acts as a view for this.state.components in App component.
UI elements rendered by StackEditor can be moved around, and to synchronize state of App I do it as below:
<StackEditor
components={this.state.components}
onLocationChanged={this.handleLocationChanged} />
In handleLocationChanged I update the state:
handleLocationChanged(e, data) {
this.setState(prevState => {
// event data copied to state here
return {components: prevState.components};
});
}
As state is now updated, this forces StackEditor to be rendered again, as its property components is bound to state as components={this.state.components} (see in the code snippet above).
This all works, but now I started questioning if I'm doing it right.
Q1: Should I be using state instead of props?
It seems that location of component is mutated in principle, although from StackEditor point of view, it is immutable (I can decide that change is invalid and not to update the state in event listener).
Q2: Is it possible to share part of the state between 2 components in React?
If I somehow convert StackEditor from getting components from state instead of props, will I get notification on state changed by child component (StackEditor) in my parent component (App)?
Q3: Also, are props more convenient to use than state in general?
When I created another component following HOC guidelines (https://reactjs.org/docs/higher-order-components.html) I discovered that props are easily forwarded to "wrapped" component, but not state. If I provide a function to call back via property (as I did above), "wrapped" component can easily call it, without even noticing that it's "wrapped". I don't see how I can easily notify "wrapped" component about state change in "wrapper", without writing some extra code.

If you imagine your application to be a tree of components in a well designed app it's usually like this:
the leafs are stateless components . They decide how data is rendered.
the nodes are stateful components. They decide which components and data to render.
Q1: Should I be using state instead of props?
It depends on which category of components you have (node or leaf).
Q2: Is it possible to share part of the state between 2 components in
React?
If you feel that your app has a lot of state that mutates and needs to be used by several components spread over your tree you usually start to introduce an external state management library (e.g. redux). Components can subscribe to your store and become stateless as your store now handles the state.
Q3: Also, are props more convenient to use than state in general?
They solve different problems so you can't really say that. A stateless component is usually easier to understand but has no capabilities to control anything.
Also read Identify where your state should live and When to use redux.
All that is only a rule of thumb. A lot of the time you will have components that have both state and props because they control parts of your app but delegate other parts to their children.
This all works, but now I started questioning if I'm doing it right.
As far as I can see from the code you provided this looks pretty much as it has to.

Related

Redux/MobX - Do I need to pass data in child components via props in React?

I know It may sound like a dumb question, But I am not able to get this solved in my head. Please bear with me.
In case when we use a state management system in React like Redux / Mob X, I guess the main purpose of these state management techniques is to provide a single source of Data and a more structured approach of updating it.
Say, I am Using a state management library(MobX) for React, And suppose I have a parent component which makes an http API call and updates the MobX store with the API response. Now I need that data in one of child/nested components.
My Question is, Should I pass that data as a prop to child component or should I enable child component to connect with Central Store and directly get that data ?
by connecting the child to store, I am turning the Child into a class component, which is making it more heavy and React optimisations may not apply. I am defeating the whole purpose of a functional component.
Awaiting replies.
Best Regards,
Lalit
This completely depends on the situation. I would suggest splitting your components up in 2 parts:
Components that could be re-used in other projects
(Higher level) Components that are so specific to this project that they probably never will be re-used.
For components of category 1, I would suggest not using mobx store directly, but instead make pure react components. (eg think of a dropdown, or an ajax dropdown component).
For second part components (think of, header, footer, section components specific for your website). just make them directly interact with the Mobx store, so that you can way quicker code what you need (instead of constantly having to prop everything).
addition
For components of category 1 you can always wrap them with the #inject() method. This way for example you could turn a dropdown component into a UserDropdown component that uses the mobx store for its state. (The inject method injects mobx state as props in the component).
const UserDropDownComponent = mobx.inject(stores => ({users: stores.userStore.users}))(DropDownComponent);
// usage:
<UserDropDownComponent />
Warning
For pure components wont always see changes of mobx state. To Fix this you need to wrap the component in an #observe annotation. Or you have to inject the props by wrapping it into: mobx.toJS(yourMobxStateProperty)

It's a good pattern to put function in a ReactJS state?

I don't feel right to store a function in a reactjs state, but not sure any disadvantage? Could anyone help analyze it?
view1: function() {
return <div>view1</view>
}
view2: fucntion() {
return <div>view2</view>
}
goView1: function() {
this.setState({contentView: view1})
}
goView2: function() {
this.setState({contentView: view2})
}
render: function () {
return(
{this.state.contentView()}
)
}
There're a few common gotchas about state in react:
Don't mutate state directly, use setState instead
Don't use state when not referenced in render, use instance variable instead.
Well, it seems fine to use state as function, since it's used in your render function to return what to render? Alright, it might not be an anti-pattern, but a better place to put those functions might be in your props, aka render prop, a few reasons:
Think state as your component's data model.
Data are not stale, it changes over time, it could be results from async operations, ui states after user interactions, controlled forms values etc.
Just like redux stores your app's global state, react state should store your component's local state that changes over time, while functions most of time, does nothing more than deferring execution.
Render props is different, it offers IoC (Inversion of Control) for free.
Props most of time similar to local state, should be concerned with UI rendering. However, unlike state owned/managed by component itself, props are passed from parents/clients of the component.
Event handlers for example, event target (usually DOM elements like button, input etc) doesn't need to know how to handle events when creating the component, instead it yields control back to component client/consumer who might need to use setState in its handleEventName handler to update certain container's state shared across children.
Some library (e.g., react router4) also shifted from HOC to render props (e.g., react 16.3 new context API - provider/consumer pair) in favor of its flexibility and explicitness. Instead of composing HOCs before runtime for static version of final enhanced component, you can declare what to render using render props and composing them at runtime in render functions. Thus, you get a clear separation between data (state/props) provider and consumer (where render props are passed from).
Regarding any performance (re-render) concerns, i think it's totally fine to use state as function, since most performance tricks are done by using shouldComponentUpdate hook with shallow compare state/props references (e.g. React.PureComponent, Redux Connect etc), so it's where immutability and memoization comes into play.

React state vs. Redux state (real usecase)

I have read multiple tutorials how to make CRUD in React with Redux bot none of the authors explained why they are using Redux. (Like they are only using it for fancyness or because all other are using it.)
Citate from here:
People often choose Redux before they need it.
Through further researching i learned that Redux is good for:
Share state between components
Let some data be accessable in the entire application
It does not exist a wrong or right. But only the do what makes sense.
My usecase
I have a component that uses a shared component:
¦-- domains/FooManagement/Components/Editor.jsx <-- Most-parent of the editor
¦-- domains/FooManagement/Components/..the children of Editor.jsx
¦-- shared/Components/Tabs/Tabs.jsx <-- Most-parent of the tabs
¦-- shared/Components/Tabs/..the children of Tabs.jsx
Tabs.jsx is used in Editor.jsx.
Which is the right approach?
Approach 1: React state (I think its the right one)
Every dynamic rendering that can happen is stored in the state of Editor.jsx.
onClick on a tab (nested shared component) calls a callback written in Editor.jsx that updates the state in Editor.jsx. This state change then rerenders the new active tab
That means that on every other component like Editor.jsx that uses the same nested Tabs.jsx, the changes for the tabs must be handled in the editor.
Code example:
/**
* domains/FooManagement/Components/Editor.jsx
* or
* domains/BarManagement/Components/Editor.jsx
*/
onTabChange(activeTab) {
this.state.activeTab = activeTab;
this.setState(this.state);
}
I think this is the right approach because:
I dont need the state of the editor or the tabs component in the entire application. But only on this view one time. Like the short term duration definition.
Approach 2: Redux state
Editor.jsx has its own state
Tabs.jsx has its own state
States are stored in Redux
Editor.jsx dont passes data down to Tabs.jsx because Tabs.jsx takes the data from the Redux store
Benefit:
The code example above must not be in Editor.jsx because its not the editor's interests how the tabs component behaves. (Or should the editor interests?)
I think this is bad because
Its too much magic in here. Immagine there comes more components in the editor like sortables, tables, etc. In the Editor.jsx you will not see what can render your view. It is hidden in the other components.
But if its all handled in Editor.jsx, you have the overview and the control of all what must be rendered on any change.
What is the right approach for you?
speaking of real usecases, I'm working on an everyday growing project, at first, pure React state management seemed like a very convenient way to develop, and it was working just fine when the components structures were still somehow flattened, but as we go along it, the project gets more complicated and by complicated I mean, more component become nested, and one parent has a serie of nested children, so we have to pass props all the way from the parent to the most furthest child, and whenever we need to rerender the parent, all the children have to go through this cycle also, as for your case, if you know that your project won't get way more complicated, and Tabs.jsx won't have maybe something like form that contains further nested subForm that contains a Grid maybe, you surely don't need to complicate your life with Redux, but as I stated earlier, for us we started to notice that at this stage, integrating Redux would be considerable

react / redux: components fetching data from state without making the API call to get that data

I'm working on a redux/react app. We started with very few "connected" components (ie, components that access the redux state and dispatch actions directly). This resulted in every component passing down way too many props to all their children, and subchildren, etc, and the top-level "connected" components becoming god classes.
So, we're making many more components connected, and able to directly access redux state and dispatch actions via mapStateToProps and mapDispatchToProps. It's much nicer, and recommended by Dan Abramov here: https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.lye71jwmx
My question is, is it OK for a child component to fetch data from the state tree, assuming it's parent has sent the action which made the actual API call to get that data into the state tree?
To give a concrete example, using the classic "blog" app:
A <blog id=123/> component will render a blog post. It will make an API call that, in one hit, fetches the blog and it's nested comments as JSON.
That component will render a <comments blog_id=123 /> component. Is it OK for that child component to just assume that the parent has taken care of the API call to fetch the blog and it's nested comments, and therefore just fetch the comments from the state tree, and gracefully render nothing if the data doesn't exist yet (ie, the API call is still in progress)?
If not, what's the alternative here?
I understand in this contrived example, you'd probably just pass comments down as props. But in my real life example, it's much more complex.
So the question is, is it bad practice for a component to say "I'll render stuff from the state tree - but whoever uses me must make the API call in order for me to work properly"
Of course that's OK. That's how I'd approach it.
With your example the child component won't render anything until the appropriate props are passed to it or state connected to it. You can pass this down to this child or fetch it from the Redux state tree, what ever works in your case.
If there are many child components or the target child is deep within the children I usually try to avoid passing down props. It's probably ideal and less cumbersome to fetch it's props from the state tree over passing state from child down to child and so on.
Take advantage of the mapStateToProps function to only pass defined props and allow the component to render what it's been given.

ReactJS: Why is passing the component initial state a prop an anti-pattern?

I've created a small ReactJS dashboard with the help of SocketIO for live updates. Even though I have the dashboard updating, it bugs me that I'm not quite sure if I did it correctly.
What bugs me the most is the Props in getInitialState as anti-pattern post. I've created a dashboard that gets live updates from a server, requiring no user interaction beyond loading the page. From what I've read, this.state should contain things that will determine whether the component should be re-rendered, and this.props.... I don't know yet.
However, when you initially call React.render(<MyComponent />, ...), you can only pass props. In my case, I get all data from the server, so the initial props just end up in this.state anyway. So all of my components have something like this:
getInitialState: function() {
return {
progress: this.props.progress,
latest_update: this.props.latest_update,
nearest_center: this.props.nearest_center
}
}
Which, unless I've misinterpreted the aforementioned blog post, is an anti-pattern. But I see no other way of injecting the state into the Component, and I don't understand why it's an anti-pattern unless I relabel all of my props to prepend initial on them. If anything, I feel like that's an anti-pattern because now I have to keep track of more variables than I did before (those prepended with initial and those without).
Disclaimer: When I answered this question I was learning / trying to
implement vanilla Flux and I was a bit skeptic about it. Later on I
migrated everything to Redux. So, an advice: Just go with Redux or
MobX. Chances are you won't even need the answer to this question
anymore (except for the science).
Passing the intial state to a component as a prop is an anti-pattern because the getInitialState method is only called the first time the component renders. Meaning that, if you re-render that component passing a different value as a prop, the component will not react accordingly, because the component will keep the state from the first time it was rendered. It's very error prone.
And here is what you should do:
Try to make your components as stateless as possible. Stateless components are easier to test because they render an output based on an input. Simple like that.
But hey.. my components data change.. I can't make them stateless
Yes you can, for most of them. In order to do that, select an outer component to be the state holder. Using your example, you could create a Dashboard component that contains the data, and a Widget component that is completely stateless. The Dashboard is responsible for getting all the data and then rendering multiple Widgets that receive everything they need through props.
But my widgets have some state.. the user can configure them. How do I make them stateless?
Your Widget can expose events that, when handled, cause the state contained in Dashboard to change, causing every Widget to be rerendered. You create "events" in your Widget by having props that receive a function.
Ok, so now, Dashboard keeps the state, but how do I pass the initial state to it?
You have two options. The most recomended one, is that you make an Ajax call in the Dashboard getInitialState method to get the initial state from the server. You can also use Flux, which is a more sophisticated way for managing data. Flux is more of a pattern, rather than an implementation. You can use pure Flux with the Facebook's implementation of the Dispatcher, but you can use third-party implementations like Redux, Alt or Fluxxor.
Alternatively, you can pass this initial state as a prop to the Dashboard, explicitly declaring that this is just the initial state.. like initialData, for instance. If you choose this path, though, you can't pass a different initial state to it aftwards, because it will "remember" the state after the first render.
OBS
You are not quite right in your definitions.
State is used to store mutable data, that is, data that is going to change during the component life-cycle. Changes in the state should be made through the setState method and will cause the component to re-render.
Props are used to pass in imutable data to the components. They should not change during the component life-cycle. Components that only use props are stateless.
This is a relevant source on the "how to pass the initial state to components".

Resources