Im using redux-thunk for API calling. While response coming back from the server, I catch them at componentDidUpdate with the simple validation as follow
async componentDidUpdate(prevProps) {
if (this.props.successCalling && !prevProps.successCalling) {
executeSomeCode();
}
}
The problem is, I'm having 2 same validation at 2 different screens, when responses are back from server componentDidUpdate both the validations are met. Hence it run both the executeSomeCode() at both different screens. How am I suppose to handle this kind of scenario?
While calling the service for a particular screen you can use a class level variable which can act as a switch like - true/ false, where this.switch will be set to false initially. on calling the service just update that class variable to true and add that variable to the if logic check as mentioned in the above example.
This way every screen will have its own switch which can be used to determine if the service call is for that particular screen or not.
Related
TL;DR React sometimes renders a loading state and sometimes not, without changes in the UI. This is probably due to batched updates.
I would like to know if the problem below is due to batched updates. If the answer is "yes", I would like to know if there's preferred way to opt-out of batched updates in React to get deterministic render behavior. Go down to "Experiment" if you want to skip the setup.
Setup
Here's the setup, a chart that takes a long time to render. So long that the render is blocking. There are three different ways to render the chart here:
one is the normal way
one with a "mounted" render hack
one with the same "mounted" render hack, but with an additional setTimeout
Option 2 & 3 both have a small useState to check whether they've been mounted. I do this to show a "Loading" state conditionally:
function ChartWithMountHack({ data }: { data: Data }) {
// initially not mounted
const [isMounted, setIsMounted] = useState<boolean>(false);
useEffect(() => {
// "Now I've been mounted!"
setIsMounted(true);
}, []);
return !isMounted ? <p>Loading</p> : <Chart data={data} />;
}
I did this, because I want to show a "Loading" state instead of a blocking render, so e.g. page switches or ternary rendering (e.g. hasData ? <p>No data</p> : <Chart />) are shown immediately, instead of blocking. (If there are better ways, please let me know!)
Experiment
Now, each button will render one of the three options/charts. Again, the second and third chart have a small hack to check whether they're mounted or not.
Try clicking on the first button and the second button back & forth quickly.
You will see that sometimes the "Chart with mount hack" will ("correctly") render the "Loading" state, but sometimes it just doesn't render the "Loading" - instead it blocks the render up until the chart is finished rendering (skips the "Loading" state).
I think this is due to the render cycles and whether you get the two updates in one cycle of the batching. (first: isMounted === false -> second: isMounted === true)
I can't really tell how to reproduce this, hence the "nondeterministic" in the title. Sometimes you also have to click on "Regenerate data" and click back & forth after that.
Cross-check
Option 3 ("Chart with mount hack with timeout") ALWAYS gives me the "Loading" state, which is exactly what I want. The only difference to option 2 is using a setTimeout in the useEffect where isMounted is set to true. setTimeout is used here to break out of the update batching.
Is there a better way to opt-out of the batching, so isMounted will always render with its initial value (false)? Using setTimeout here feels like a hack.
React has concurrent features to handle these sort of things, for example React Suspense tags or you make use of Subscription libraries like Rxjs, which its subscription should be done in the componentDidMount and componentWillUnmount to unsubscribe the data.
Then the isMounted is just a work around for a pending issue, probably from the library you're using or sometimes just your bundler/build tool acting out a bit.
lastly to avoid unnecessary re-render, you can use React memoization of component using React.Memo.
Kindly read more on these.
i have problem in react and long time i can't figure out with this.
I can't understand what happened.
What a scenario:
My app using React and Redux. I keep all my state in redux.
i set some dataRefreshed state to redux state for handling re-rendering page when data updated from api.
i'm using componentWillReceiveProps lifecycle method.
in my redux state
let initialState = {
dataRefreshed: false
}
when my request starting, in redux
case START_REQUEST:
return {
...state,
dataRefreshed: false
};
case SUCCESS_REQUEST:
return {
...state,
dataRefreshed: true
};
So in my component when i make request and get from api new data:
componentWillReceiveProps(nextProps) {
if (nextProps.Reducer.dataRefreshed) {
apiCall();
}
}
so if thinking with logic:
1- when my request start and request getting ok status, my dataRefreshed setting true
2- and here nextProps.dataRefreshed and this.props.dataRefreshed not equal.
Till here everything work well. my Condition working and apiCall() runned.
but apiCall function runned 10 times
why my state toggling one time so my state turning one to to true from false. But inside condition my function calling million times.
i can't understand what is the logic here.
I'm seriously think anymore living react because of that
This is what your code actually does:
set dataRefreshed=true
trigger props change
call apiCall() (cause dataRefreshed==true)
START_REQUEST: setting dataRefreshed=false
trigger props change (does nothing cause dataRefreshed==false)
apiCall got response from server,
SUCCESS_REQUEST: setting dataRefreshed=true
goto 2 (infinite loop)
You should introduce some flag like shouldRefresh, which will be set to false once data is fetched and not automatically set back to true unless it is meant to.
Is not that it is doing it twisted. The problem is componentWillReceiveProps method, that’s why react remove it to avoid this type of things
Update: Here is an example Pen
https://codepen.io/anon/pen/vwzGYY?editors=0011
Preface
Based on my research, it seems like I need a completely different approach. Maybe you can suggest one?
Context
I'm using a Redux-Form (technically an older version, but the API's
in question seem really stable. We can burn that bridge when we get there.) to set some "filters" for a sort of search results list.
In particular, since I want the pages to be link-able, I'm also setting the form content in the URL query params, via React-Router, or initially setting it on page load via similar mechanism.
The only field so far is "organization_name", a text field, used to set the query param value, and trigger an API request for /endpoint?name={some_name}.
E.g.,
<Field
name="organization_name"
component="input"
type="text"
placeholder="Organization Name"
value={value}
/>
I've tried several things, but here's a recent shot:
I'm grabbing reset, change, and other things from default props. I'm passing in a handleSubmit as required.
handleSubmit works correctly, to do some state updating, set/push the URL query params with React Router, and then make a new API call/update display of new results! Woot!
What I want / expect
In the long run, I would like a "reset filters" button that sets all filter values back to defaults (e.g., set the "name" value to empty string), and re-submits the form (thus triggering handleSubmit).
What I first tried to implement was a button, as such:
<button
name="reset_filters_button"
type="button"
onClick={resetAndSubmit}
disabled={pristine || submitting}
>
Clear Search
</button>
Where resetAndSubmit is defined on the form container as such:
const resetAndSubmit = event => {
reset();
handleSubmit();
};
What actually happens... (submit takes precedence over dispatched events?)
Using the Chrome dev tools debugger, I can clearly see that the reset method is called, and returns it's dispatch(...)'d event. However, the form and state values are not updated before handleSubmit() runs and submits the form.
I think this might have to do with the submit event taking priority?
I have also tried something janky, like importing change (default prop for the container) and defining the reset button thus:
<button
name="reset_filters_button"
type="button"
onClick={() => {
change('organization_name', '');
methodThatDispatchesSubmitAction();
}}
disabled={pristine || submitting}
>
Clear Search
</button>
Which (if I remove methodThatDispatchesSubmitAction()) works correctly to set the field value back to blank, making the form technically "pristine" again as well.
methodThatDispatchesSubmitAction() (if it's not obvious) is bound on the parent via dispatchToProps, and passed in to the form container, where it uses the "remote submit" suggestion, e.g,
// organization_list_filter == name of the Redux-Form to submit.
dispatch(submit('organization_list_filter'));
TL;DR and final question:
How does one properly reset a form and submit its' default/empty values?
Every time I dispatch or directly call Redux Form 'submit', it ends up submitting the form before clearing values from state, or the UI. I have walked through this with a debugger and it's not skipping my call to reset or change. It's like an async/race issue, but I admit I am out of my league in this particular case for sure.
Am I just Straight Up Doing It Wrong?
It is most definitely a race condition issue (or since we aren't actually dealing with threads, an order of events issue).
The reason using a methodThatDispatchesSubmitAction works when your current example does not, is because a dispatched action has the benefit of reading data directly from the redux store. Your example is not reading from the redux store, it's reading from a property that is passed in. Yes, this property comes from the redux store, but the problem you are seeing is that it hasn't been updated in your component yet.
Bear with me as this next piece is not going to be entirely accurate but it should suffice to explain what you are seeing.
Submit is clicked
-> Reset action is dispatched
-> Reducer receives action and returns updated state
-> Handle submit is fired using values prop (old state data still)
Component is updated with new props from redux state
As you can see, the order of events don't allow for an updated state to be given to the property until our click code has finished running. If you've ever watched a video on the JS Event Loop (I highly recommend it), you'll know that our onClick handle will run in full before any other async operations (or sync operations that come after our click) have a chance to run.
There are good reasons why Components aren't given updated props right away but the primary one is performance. You can see that this order is in fact the problem by wrapping the handleSubmit in an async event that fires immediately (it doesn't actually fire immediately, all other sync/async operations queued before it will finish).
const resetAndSubmit = (event) => {
reset();
setImmediate(() => handleSubmit());
}
This changes the order of events as follows:
Submit is clicked
-> Reset action is dispatched
-> Reducer receives action and returns updated state
-> Handle submit is queued on the event loop (not run yet)
Component is updated with new props from redux state
Event loop reaches queued code and runs is
-> Handle submit is fired using values prop (new state data)
Hopefully, this helps you understand why the problem is occurring. As for solutions to fix it. Obviously, you can queue the handle submit as I've shown above. Another option would the one you've described as using a dispatch to perform the submit. A third option would be to use something a bit heavier like redux-thunk or redux-sagas that tie the resetAndSubmit action into a single dispatch. Although honestly, this is the same as option two, just reduced into a single dispatch. Option four, don't use redux for all your data. Obviously, this fourth option comes with trade-offs but my point being, just because you are using redux in a project doesn't mean every single piece of data needs to be in redux. Though it completely defeats the purpose of redux-forms.
I should also add, you are not alone in being confused by this. When you introduce redux, it messes with how you traditionally think about working with code. Normally you think, I do A then B. But with redux, you do A, wait for A's changes to make it through the system, and then you do B. That's where Sagas or Thunks can be nice. You move more logic to the store to act on the dispatch rather than wait for it to all make its way back down to a component via props.
The problem:
VueJS is briefly showing the "else" condition before the "if" condition loads. This is causing an unintended experience for the user because they should never see the "else" when the "if" is truthy. They should only see the "if" if the "if" is true.
The detail:
I have a custom online store and many different markets. I get back an item count from my server and if that number is zero then I say there are no items for that country, in other words the country is not open yet for this store. If the number is not zero then don't show the message and actually show the items.
Here is a slimmed down version of my code:
HTML
<div v-if="count !== 0">Items are in the store, here they are!</div>
<div v-else>Sorry no items in the store.</div>
JS
mounted() {
// Checks the location and gets items from server.
if (this.location) {
this.getItemsForHomeView();
}
}
I found this: Understanding Vue.js Lifecycle Hooks but it didn't help because when I tried moving the function out of the mounted() and into any of the earlier ones, like beforeCreate() or created() or beforeMount() I get the same result.
In addition to handling an empty item count once the data has resolved, you need to handle the case of there being no data yet to count. You didn't mention using Vue Router, but this discussion of handling async data still applies: you can either have the async fetch prevent the component from rendering at all, using a beforeMount or beforeRouteEnter hook, or wrap all the item list markup in another conditional, which is only rendered after your data has been fetched, and something like isLoaded (local state) is set to true.
I have been writing components in React.js recently. I have never had to use methods like componentWillMount and componentDidMount.
render is indispensable. getInitialState and other helper methods I wrote also come in handy. But not the two aforementioned lifecycle methods.
My current guess is that they are used for debugging? I can console.log out inside them:
componentWillMount: function() {
console.log('component currently mounting');
},
componentDidMount: function() {
console.log('component has mounted');
}
Are there any other uses?
componentDidMount is useful if you want to use some non-React JavaScript plugins. For example, there is a lack of a good date picker in React. Pickaday is beautiful and it just plain works out of the box. So my DateRangeInput component is now using Pickaday for the start and end date input and I hooked it up like so:
componentDidMount: function() {
new Pikaday({
field: React.findDOMNode(this.refs.start),
format: 'MM/DD/YYYY',
onSelect: this.onChangeStart
});
new Pikaday({
field: React.findDOMNode(this.refs.end),
format: 'MM/DD/YYYY',
onSelect: this.onChangeEnd
});
},
The DOM needs to be rendered for Pikaday to hook up to it and the componentDidMount hook lets you hook into that exact event.
componentWillMount is useful when you want to do something programatically right before the component mounts. An example in one codebase I'm working on is a mixin that has a bunch of code that would otherwise be duplicated in a number of different menu components. componentWillMount is used to set the state of one specific shared attribute. Another way componentWillMount could be used is to set a behaviour of the component branching by prop(s):
componentWillMount() {
let mode;
if (this.props.age > 70) {
mode = 'old';
} else if (this.props.age < 18) {
mode = 'young';
} else {
mode = 'middle';
}
this.setState({ mode });
}
componentDidMount only runs once and on the client side. This is important, especially if you're writing an isomorphic app (runs on both the client and server). You can use componentDidMount to perform tasks require you to have access to window or the DOM.
From Facebook's React Page
If you want to integrate with other JavaScript frameworks, set timers using setTimeout or setInterval, or send AJAX requests, perform those operations in this method.
componentWillMount has fewer use cases (I don't really use it), but it differs in that it runs both on the client and server side. You probably don't want to put event listeners or DOM manipulations here, since it will try to run on the server for no reason.
This is an example of an isomorphic web application that makes use of componentWillMount: https://github.com/coodoo/react-redux-isomorphic-example
However, I'm 99% certain that it runs the code inside componentWillMount for no reason on the server side (I think using componentDidMount to ensure it was only run client side would have made more sense) as the code which ensures that fetch promises are fulfilled before rendering the page is in server.js not inside the individual components.
There is discussion on per-component async fetching here: https://github.com/facebook/react/issues/1739 As far as I can tell, there is not a good use case for componentWillMount as far as isomorphism is concerned at least.
In my project which is a dashboarding tool, I have used componentDidMount().
On home page previously saved dashboards appear on the sidebar. I make an ajax call within componentDidMount() of component rendering Homepage, so as to fetch list of dashboards asynchronously after the page has been rendered.
Why React Life Cycle Methods?
Intend to use third-party (Ex D3.js) library with React Component
class Example extends React.component{
constructor(){
// init state
// will be called only once
}
componentWillMount(){
// will be called only once
// will not be triggered when re-rendering
// usually will fetch data that is needed in order
// to render properly from other API
}
shouldComponentUpdate(){
return false
// will not re-render itself after componentDidMount(){}
}
render(){
return (
<div id="chart"></div>
)
}
componentDidMount(){
d3.select(".chart")
.selectAll("p")
// d3.js ........
// d3.js ........
// Usually, this will trigger React to re-render itself,
// but this time will not because we have set
// shouldComponentUpdate to false
}
}
Why React wants to do this?
Since rendering DOM is an expensive operation, React uses the layer of virtual DOM to update only DOM / DOMs that is/are different from previous state.