I have a react component, In which I am using a date picker. Based on value of Date selected I am sending an ajax request to fetch data.
I am not using any frameworks like redux or flux.
export default class MyComponent extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
// Initial fetch request based on the default date
}
onDateSelectionChanged(fromDate, toDate) {
this.setState({
fromDate,
toDate
});
}
render() {
return (
<div className="row">
<DateRangePicker callBackParent = {this.onDateSelectionChanged}/>
{/* other stuff */}
</div>
);
}
}
Now suppose I changed the date to another date. What is the best way to fetch the data again? should I fire request again inonDateSelectionChanged or is there any life-cycle method?
I strongly suggest to decouple the ajax logic from your component. Remeber that plain React was build only to simplify the rendering of the views and not for complex logic like Http calls.
Using Flux you can quickly create the infrastructure for handling both the UI rendering and any other logic for your app.
The complete tutorial is here but I will add a quick summary so that you could easily get started.
Add 4 classes that will be your infrastructure:
YourComponentActions - this class will handle the "actions" that your component will fire. An action is actually an event that will be fired from your component to something that will perform the actual logic (point 4).
SharedConstans - this class will hold the event names of your app.
AppDispatcher - this class will manage the event handling of your
app.
YourComponentStore - this class will register to the action's event and handle the http call. Here is the logic of your component that is decoupled from the UI. After you receive a response from your ajax call you will fire another event from your store and your component will register to it and only then update the state.
It feels complex however from now on you will easily add any logic to your app while keeping it decoupled, readable and easy to maintain.
Read more about Flux here.
You should fire another network request in onDateSelectionChanged, there's no lifecycle method for when state changes.
Technically speaking you could do some logic in componentWillUpdate (or worse, shouldComponentUpdate) to make a request when that state field changes and it would work, but you shouldn't. Both of those lifecycle methods have well defined purposes, making network requests would make your code less clear and harder to maintain.
If you really insist on sending the request from your component method, than firing it in onDateSelectionChanged is definitely the way to go. As it responds to every Date change, it is naturally the only method capable of fulfilling your needs, and the lifecycle methods are not directly aware of the Date change nor the right place to do it. Implementing something like that in e.g. componentWillUpdate or componentDidUpdate can possibly lead to cyclic execution and that isn't something you want to face without a good reason.
Speaking of lifecycle methods, the only one explicitly recommended to fire requests is componentDidMount method, where you have a good opportunity to do some ajax initialization operations, as you can see in docs, but none of them is suitable for ordinary data fetching.
On the other hand, I suggest you really have a look at Flux, which is an architecture solving many issues, separation of concerns is on of them. Your problem here is that you tie your component to creation of Ajax requests, which doesn't promote reusability and makes your code harder to maintain. Think of components as tools to present content and capture users inputs, bothering with requests and response or processing and storing incoming data shouldn't be their concern (at least at larger scale).
You can of course separate your request creators to external functions, but if you tend to write React frontend, you will sooner or later face problems like handing props over many intermediary components or propagating events up through your component hierarchy, which is very tedious and messy without some kind of architecture, and Flux is the best solution for these issues and therefore number one technology to learn - if you mean it with React seriously.
onDateSelectionChanged(fromDate, toDate) {
var self = this; // we can not use this inside ajax success callback function
this.setState({
fromDate,
toDate
}, function() { // callback fires after state set
// your ajax request goes here, let say we use jquery
$.ajax({
url: fetch_url, success: function(data) {
// again we can setState after success, but be careful
// we can not use "this" here instead we use "self"
self.setState({
someState: data.someValue
})
}
})
});
}
Related
I'm wondering if it is bad practice to have 'fat' gDSFP functions. Currently, I have a component that takes in some data and does a bunch of data manipulation
function getDrivedStateFromProps(nextProps, prevState) {
// start doing data manipulation
and along the way if it encounters an error condition it returns a new error slice of state
const someValue = nextProps.something * myFunc()
if (someValue === badThing()) {
return {error: true};
}
// continue doing data manipulation
This repeats several times before it finishes all data manipulation and returns the derivedState that my component needs. I'm curious on what the communities views are on a 'fat' gDSFP functions. My component only runs gDSFPs when the external data source has changed and it needs to derive new state so I don't see where else this logic could live.
I think you may actually be in a situation where using getDerivedStateFromProps might not be the best approach at all. In your question you state...
My component only runs gDSFPs when the external data source has changed and it needs to derive new state so I don't see where else this logic could live.
Given this statement, it sounds like you can use memoization. Here is this concept discussed on the react docs.
The basic idea is that managing getDerivedStateFromProps can get hairy especially when you have lots of logic going on there. If the reason why you want to capture your props in state is only to get a performance boost, then memoization might be your friend.
The idea here is that you do not want some logic to run every time your props change, so what this will buy you is that if you have a function whose arguments are the same as they were before, as an example state has not changed, your function will return the last computed result which it had stored in the cache. This library handles this beautifully and is pretty easy to use.
Another concern people often have which may prompt them to reach for getDerivedStateFromProps is to ensure that their component does not render unless if the props have in fact changed, so by having the component render based off of computed state this can be achieved.
But this too can be achieved without using getDerivedStateFromProps. Using PureComponent can give you this same result with much less fuss. Another option can be shouldComponentUpdate.
In short, unless you have some very specific reason that getDerivedStateFromProps is right for your use case, you may be better off reaching for a solution that involves less hair pulling.
I would like to know how long it takes my app to become "ready" for the user to interact with it. The timeline of the app loading includes the following:
DOM load.
Initial React render.
HTTP calls triggered from various componentDidMount()s
HTTP calls return. Redux state is updated with HTTP responses.
React renders with new values from HTTP responses.
All initial loading is complete. The user is ready to interact with the app.
At the end of this process, I'd like to fire a tracking event to record the value of window.performance.now().
I'm not sure what the best way to do this is. React's component system does a good job of decoupling various parts of the UI. In this case, it, unfortunately, means that I'm not going to have one easy place to check to know "has everything been rendered with the new data".
Things I've tried or considered:
Look for a React lifecycle hook that tells me if any child is updating. Something like componentOrAnyChildDidUpdate(). I don't think this exists, and it may be counter to the React philosophy.
Hack together an anyChildDidUpdate() lifecycle hook via context and making every component in my app either subclass a helper abstract base class or be wrapped in a higher-order component. This seems bad because context is an experimental API.
Subscribe to the Redux state via store.subscribe(). Update the Redux state to have an explicit record of whether all the HTTP calls have returned. Once all the HTTP calls have returned, and React is finished re-rendering, then I know to fire the tracking callback. The problem is knowing when React is finished re-rendering. It would work if my store.subscribe() the callback was guaranteed to be executed synchronously after react-redux's callback. But that is not the case.
Is there a good way to do this in React?
I'm afraid there is not a universally good way to do this in React, this is "logic" that is related with the structure of your application.
I wanted to display a loader when navigating from one page to another in Single Page Application(SPA) written in react and I faced a similar problem not knowing when to stop displaying it and if all the components in the new page have completed their API calls/renders.
The way I resolved it was:
1) I removed all my API calls from inside my components.
2) Create a Page component to wrap all the components included in that page(invoked by your react router).
3) Perform all requests required for your components simultaneously on navigation(in my case while displaying the loader). For each request that completes, create a promise and inside it create your component dynamically using React.createElement. Pass to the component created the request response and the promise handler as props.
4) Resolve the promise in your component's componentDidMount.
5) Once all the promises are resolved you know the "page" is ready and you can record the value of window.performance.now().
It is hard to provide a minimal code example without a lot of out of context code since this code is spread across the application.
There's more than one way to do what you're asking - but off the top of my head I would do the following:
• Create a perf reducer and call performance.now() right before I make the redux store and add the value to the initial state.
{ perf: { start: '...', end: '...' } }
• Track loading status of initial HTTP requests in a loaded reducer.
{ loaded: { request1: false, request2: false, request3: false } }
• Connect top level component to loaded reducer and check if all requests are complete in componentDidUpdate. If true add end value to perf reducer.
import React from 'react';
import { connect } from 'react-redux';
class App extends React.Component {
componentDidUpdate(prevProps) {
if (!prevProps.loadingComplete && this.props.loadingComplete) {
this.props.updatePerf(performance.now());
}
}
}
const mapStateToProps = state => ({
loadingComplete: state.loaded.every(item => item),
});
const mapDispatchToProps = dispatch => ({
updatePerf(time) {
dispatch({ type: 'SET_ENDING_PERF', payload: time });
},
});
export default connect(mapStateToProps, mapDispatchToProps)(App);
In our project, we use redux and a couple of actions - trigger, request, success, error.
"Trigger" calls request and throw loading: true into our "smart" component
"Request" fetch data and throw them into Success/Error
"Success", tells us that everything is fine and data loaded and throw { loading: false, data }
On success/error, we always know that is happening with our application
And of course you can use componentWillReceiveProps(nextProps) {} and check loading flag and data in your component
You can try to use react-addons-perf
That's how I benchmark my apps usually:
Basically you want to start measuring when your component starts updating and stop the measurement after the lifecycle method componentDidUpdate().
import Perf from 'react-addons-perf'
componentWillMount() {
window.performance.mark('My app');
}
componentDidMount() {
console.log(window.performance.now('My app'));
Perf.start()
// ... do your HTTP requests
}
componentDidUpdate() {
Perf.stop();
Perf.printInclusive();
}
Like that you will track your component initial render + your component updates.
Hope it helps
Two steps to achieve this.
Track all HTTP-requests via actions
Simple counter in redux state would be enough, that increments on start of request and decrements on success or fail (all via appropriate actions).
No window.dirty.stuff here in front of Dan Abramov.
Track all connected components
componentDidUpdate method indicates that all children finished rendering. This can be achieved without much boilerplate with recompose's lifecycle HOC. Right place to start tracking re-render might be sCU method or just cWRP if you use recomposes shouldUpdate or reselect already - since we won't track components that didn't update.
Note that all is assuming idiomatic react/redux app, no tricky side-effects or animations. For example, if some child component somewhere deep in the hierarchy fires its own AJAX request, say on cDM, not via redux action. This way you have to track them too, BUT no one can be sure if they imply any re-renders.
Tracking such behaviors is still possible, just might require more effort.
from a design POV, in my opinion being ready or not is a user presentation property and so should be handled by react components alone.
for example, you may later decide to allow the user to interact with some part of your UI while some other parts are still loading, or you may decide that some components should allow the user to interact before the data model is ready, etc ... in other words, it's a (react) component responsability to tell if/when it's ready or not and nobody else.
That is, all 'waitable' components could expose an onLoad-like prop to be passed up the react tree; the root component would then coordinate the result by changing the tree down stream accordingly by propagating the appropriate props down to leaves.
This could be implemented by writing a mixin/high order component to incapsulate the "readyness update" logic.
After struggling too much with Redux, flux and other pub/sub methods i ended up with the following technique. I do not know if that can cause some big damage or flaws so posting it here to get some light from the experienced programmers about its pros and cons.
var thisManager = function(){
var _Manager = [];
return{
getThis : function(key){
return _Manager[key];
},
setThis : function(obj){
_Manager[obj.key] = obj.value;
}
}
};
var _thisManager = new thisManager();
// React Component
class Header extends Component{
constructor(){
super();
_thisManager.setThis({ key: "Header", value:this}
}
someFunction(data){
// call this.setState here with new data.
}
render(){
return <div />
}
}
// Then from any other component living far somewhere you can pass the data to the render function and it works out of the box.
i.e.
class Footer extends Component{
_click(e){
let Header = _thisManager.getThis('Header');
Header.somefunction(" Wow some new data from footer event ");
}
render(){
return(
<div>
<button onClick={this._click.bind(this)}> send data to header and call its render </button>
</div>
);
}
}
I am sending json as a data in my application and it perfectly renders the desired components and i can invoke the render without any pub/sub or deep passing down the props to invoke a parent method with a changing this.setState to cause re-render.
So far the application works fine and i am also loving its simplicity too. Kindly throw light on this technique pros and cons
Regards
EDIT:
It is bad to call render so i changed it to another method to get more pros and cons of this setup.
Two main concerns with this setup:
1. You should never call react lifecycle methods directly
2. Backdoors into components are a bad idea, which destroy react's maintainability
Ad 1:
If you invoke render() (or any other react method) directly, react probably does not call componentDidMount(), componentDidUpdate()` and other lifecycle methods in the component tree.
Dangers are:
Many designs with react component rely heavily on the lifecycle methods being fired: getInitialState(), componentWillReceiveProps(), shouldComponentUpdate(), componentDidMount(), etc etc. If you call render() directly, many components will likely break or show strange behaviour.
You run the risk of breaking react's difference engine: through life-cycle management, react keeps a virtual copy of DOM in its (internal) memory. To work correctly, the integrity of this copy if vital to react's working.
Better would be (but still in violation of my second point):
Include a different method inside the component.
Which has a setState() if you want to re-render.
And call that method from the outside.
Ad 2.
A direct reference to a mounted component (as your thisManager does) has some additional risks. React's designs and limitations are there for a reason: to maintain unidirectional flow and component hierarchy with props and state, to make things easy to maintain.
If you break this pattern - by building a backdoor into a component, which allows manipulation of state - you break this design principle of react. It is a quick shortcut, but is sure to cause great pain and frustation when your app grows.
As far as I know, the only acceptable exceptions to this rule are:
Methods inside a component that respond to ajax call results, to update state (e.g. after fetching data from server)
Methods inside a component to handle triggers from its direct descendent children components (e.g. run validation on form after a child button has been clicked)
So if you want to use it for that purpose, then you should be fine.
Word of warning: the standard react approach guards random access to components, because the invoking component or method needs to have a reference to the component. In both examples such a reference is available.
In your setup, ANY outside piece of code could lookup the ref to the "header" in your table, and call the method which updates state.
With such indirect reference, and no way of telling which source actually called your component, your code is likely to become much harder to debug/ maintain.
The general problem: Let's say I have a button with an onClick handler calling an action creator. The action does an ajax call which dispatches a message when ajax responds, and this in some way affects the UI. Given this basic pattern there's nothing stopping the user from clicking this button multiple times, and thus running the ajax call multiple times.
This is something that doesn't seem to be touched upon in the React or Flux documentation (as far as I have seen), so I've tried to come up with some methods on my own.
Here are those methods
Use lodash.throttle on a method which does an ajax call so that multiple clicks in quick succession don't create multiple calls.
Use lodash.debounce on a method so that ajax is only called once a user hasn't done any activity for a bit. This is how I'm doing semi-realtime updates of text fields on change.
Dispatch an "is updating" message to stores when the action is first called and then dispatch a "done" message when the ajax call returns. Do stuff like disabling input on the initial message and then re-enable on the second.
The third method seems to be the best in terms of functionality since it allows you to make the user interface reflect exactly what's going on, but it's also incredibly verbose. It clutters absolutely everything up with tons of extra state, handler methods, etc...
I don't feel like any of these methods are really idiomatic. What is?
Hal is pretty much correct. Dispatching multiple messages is the Fluxiest way to go.
However, I would be wary of dispatching an IS_UPDATING message. This makes reasoning about your code harder because for each AJAX action you're dispatching several actions at once.
The idiomatic solution is to split your AJAX "actions" (action-creator-actions) into three dispatched actions: MY_ACTION, MY_ACTION_SUCCESS, MY_ACTION_FAILURE, handling each instance appropriately, and tracking "pending-ness" along the way.
For example:
// MyActionCreator.js
// because this is in a closure, you can even use the promise
// or whatever you want as a sort of "ID" to handle multiple
// requests at one time.
postMessage() {
dispatch('POST_MESSAGE', { ... } );
api.slowMessagePostingAjaxThingy().then(
(success) => { dispatch('POST_MESSAGE_SUCCESS', { ... }); },
(failure) => { dispatch('POST_MESSAGE_FAILURE', { ... }); }
);
}
// MyStore.js
on('POST_MESSAGE', (payload) => { /* do stuff */ });
on('POST_MESSAGE_SUCCESS', (payload) => { /* handle success */ });
on('POST_MESSAGE_FAILURE', (payload) => { /* handle failure */ });
This gives you several benefits over your alternate solutions:
Your store is exclusively in control of whether an item is pending or not. You don't have to worry about changing UI state on actions in your UI code: you can have your UI look exclusively to a pending property of your store for truth. This is probably the biggest reason for using Flux over MVC systems.
You have a clean interface for taking your actions. It's easy to reason about and easy to attach other stores to this data (if you have a LatestMessageStore or something, it's easy to subscribe to these events). This is the benefit over using IS_UPDATING as Hal suggested.
You save your lodash calls for when they semantically make sense— like when you may be inundated with legitimate data (a text field).
You can easily switch between optimistic updates (change the store when POST_MESSAGE is called) or pessimistic updates (change the store on POST_MESSAGE_SUCCESS).
I would argue that the third method is the correct way, but I don't find it to be verbose. A lot of React code that I see written sort of misses the spirit of React with its idea of very small, composable components. When large monolithic components are created, yes, things can get very messy.
But if the button in question is its own component, then it can take care of rendering based on its state. When a user clicks the button, the state of just that component changes -- and it renders it in a way that it can't be clicked again.
Once the store has notified that component that it has changed, the component can set its state back -- and with it, re-render itself.
It's a pretty straight-forward process; it just requires thinking about pages as a collection of small, composable units.
Having spent some time working with flux (both ‘vanilla' and with various frameworks including alt and fluxible) I am left with a question about best practice with regard to loading the initial state of components. More specifically about components directly accessing the store to do it.
The flux ‘model’ prescribes a unidirectional flow of data from Action>Dispatcher>Store>View in a loop, yet it seems this convention is eschewed when loading the initial state of components, most docs/tutorials contain examples where rather than firing an action to get the data, the component calls a function on the store directly (examples below).
It seems to me that components should have little/no information about the store, only about the actions that they can fire, so introducing this link seems both unintuitive and potentially dangerous as it may encourage future developers to jump straight to the store from the component instead of going via the dispatcher. It also runs counter to the ‘Law of Demeter’ which Flux is supposed to adhere very strongly to.
What is best practice for this? Is there a reason that this always seems to be the case? Its quite possible that I have missed out something fundamental, so please let me know if so!
Thanks.
Examples of components calling the store directly.
Flux React example from the fb flux repo example chat app (https://github.com/facebook/flux/tree/master/examples/flux-chat)
MessageSection.react.js
getInitialState: function() {
return getStateFromStores();
},
function getStateFromStores() {
return {
messages: MessageStore.getAllForCurrentThread(),
thread: ThreadStore.getCurrent()
};
}
Another example from the same repo for the TODOapp
(https://github.com/facebook/flux/tree/master/examples/flux-todomvc)
TodoApp.react.js
function getTodoState() {
return {
allTodos: TodoStore.getAll(),
areAllComplete: TodoStore.areAllComplete()
};
}
Example of the alt implementation of the above todo app: (https://github.com/goatslacker/alt/tree/master/examples/todomvc)
TodoApp.js
function getTodoState() {
return {
allTodos: TodoStore.getState().todos,
areAllComplete: TodoStore.areAllComplete()
};
}
and finally the alt specific tutorial:
(https://github.com/goatslacker/alt-tutorial/blob/master/src/components/Locations.jsx)
Locations.js
componentDidMount() {
LocationStore.fetchLocations();
},
It depends on how the structure of you app looks like. Often you want to fetch some data before showing something to the user. What I have found to be a good practice is to have a high end component which fires on mount an action which fetches any initial data from an API. This means that when this action is done fetching it calls the store which caches the data and then emits a change.
This change emit then sets in motion the re-rendering of the whole application.
This way you keep the uni-directional data flow. The whole point with Flux is letting the user extract the data flow functionality out of components to keep them more clean, discourage components to directly communicate with each other and decrease the amount of unnecessary properties which has to be passed around the application.
In the examples the initial state fetches some initial value from the store. This is a common way to fetch the initial value, but you could set it in the component as well. Both ways I would say is a good practice. This does not mean that every component is free to fetch whatever they like from the store.
Anyway, the goal would be to keep the code and data flow as intuitive as possible with Flux. All of this are reasons why there are so many implementations of Flux.