Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 12 days ago.
Improve this question
im new to react and I came into a problem I cannot seem to fix,
Im trying to reacreate the iPhones notes app and theres this issue that when I first hit + to add a new note it doesnt get added into the state array, whats weird is that it works normally the second time I click it and so on
My 2nd issue is that theres this "activeObj" state variable which stores the clicked notes object but also normally works on the 3rd try, the first and second clicks look like this (check screenshots)
I tried changing the syntax and the structure of the functions but my skills are still limited since its my first week of doing react
When you call the setState method, it updates the state behind the scenes, and then schedules a re-render of your component with the state variable (e.g. arrayOfNotes) set to the new value. Because you've got your console.log inside the function that's calling the setState method, you're logging the old value, because it hasn't done the re-render yet.
Next render cycle it'll be fine, in fact you could move your console.log into the body of the component and see it'll behave as you're expecting.
When you're updating a state and the new state value depends on the previous one, I'd also recommend using the function version of setState precisely for this reason, e.g.
setArrayOfNotes((prev) => [newNoteObject, ...prev])
This is because prev will take into account other sets done this render cycle, but the way you're doing it currently won't. Doing it this way will certainly save you from other bugs later on.
The cycle order also is what's causing your second issue. You're setting the active note, but because the set won't apply until the next re-render, activeNote will still be the old value in the line below, when you're expecting it to already have been updated. You can just pass id in there instead in this case.
Related
I am building a Quiz application using React and I am fetching the questions as an array and maintaining the states:
Array holding all the information about all the questions- statement, options, chosen answer, status(answered, marked for review, unvisited);
object with all information about the current question being displayed
index of current chosen answer (Among the 4 radio buttons)
Now the problem is that when I chose an option and click on 'Save and go to next question' the following events are triggered:
Update current question info (new status and chosen answer)
The array of all questions is updated with the new information for the current question
Go to next question (Update the state #2 (currentQuestionInformation) with the next question
and set #3 to the previously chosen answer for that question (if chosen))
Now the problem is that it is very important for these events to be triggered in sequence else when we go to the next question even if we have answered it and come back to it the state #3 is not updated properly.
In my code since I am using react hooks the state updation is asynchronous and I am not getting the right sequence required. The next question function is triggered before the array with the information about all questions is updated.
I read a lot of answers but all of them suggested using the Effect Hook. But the main problem is I don't have a generalized use case for the setStates.
For example I won't go to the next question necessarily after the total array is updated and this is one particular situation where I need to trigger goToNextQuestion() after state #1 is updated.
What should I do to achieve my required goal?
You can have a single useState hook that has an object with all those states. When updating, you can then update them all at once.
const [myState, mySetState] = useState({questions:[],current:{},selected:0}
Then when updating, copy the old value, destructuring it and replace with the new info
mySetState({...myState, current:newValue, selected:newSelected})
I have a couple set states on providers that trigger a bunch of effects throughout my react app. They happen back to back in a hook. The second set state has some effects that it triggers that need make sure that the first hook fully propagated through the app. Currently the first one has not made all the required changes so some functionality triggered by the second causing weird behavior. How do you ensure that the second one only happens after the first is fully propagated?
setSomeStateValue(x);
setValueToTriggersEffectsThatRelyOnUpdatesFromTheOther(y);
Here are some thing I have done that work but have their issues:
1.) settimeout(...,0)
setSomeStateValue(x);
setTimeout(otherSetState,0);
This pushes the second one to a subsequent batch. I like this one because it doesn't involve adding extra code to watch other state variables that the code maybe shouldn't be concerned with, but it does seem a little black magicy and could possibly cause hard to debug issues.
2.) monitor the stuff i need set before calling the second set state
This one seems a little more readable but involves importing and watching things that might not make sense that they belong in the related code. Basically adding a useEffect that watches everything I need set before the second call happens. Also if something changes in regards to what is needed to have the second call ready then this code will have to change as well where as the first solution should not require an update.
Both of these work but have their fallbacks. I would like to refactor the second call to account for these issues but that would be too large of a refactor at this point too make it a feasible option. Is there a native way to ensure this or another strategy here that I am missing? And if not, which one of the above solutions is better?
In such situations where a setState is dependent on a previous setState or a specific state of the component, you can potentially do two things. First,
use the second argument of setState. Here, callback is only invoked once setState is done updating the state. Hence you can get the desired synchronous behaviour.
setState(updater, [callback])
Use componentDidUpdate lifecycle method ( For Hooks, it would be just another useEffect ). If you don't want to have complex setStates in your component, simply have an effect with a dependency on the needed state and do your operations there
React.useEffect(() => {
if( desired_state){
secondSetState()
},
[ desired_state ]
}
I am trying to understand more about React, so I did some very simple test.
I know my test is NOT react way of doing things, but since it is still Javascript, I am just testing how everything is working for curiosity.
I declare a variable outside of react component, and every time the function component renders it will add 1 to the variable.
I activate the re-render by using a button, the button will activate an increase function then use a setState thus cause the component to re-render.
What I notice is the a variable is adding 1 twice, I put 2 console.log before and after it to monitor it. I can see there is one execution of adding, but where it the other adding coming from? The afteradding after rendering should be the same of next round's value before adding.
See the code, thanks in advance for any deeper understanding.
Thanks for the help, after removing the strictmode, app is behaving normally now.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I need some help here. I know there are some real smart people here.
how can i make two different links fire at the same time when somebody clicks on my link.
1. is the auto download and when that is happening at the same time they go to link 2 an explanation page or such.
i have no HTML code, nor do i know how to set it up..but I'm happy to re-compensate with a small donation.
I placed a drawing to exemplify:
Hopefully that will clear things a bit better.!
You could simply add a Javascript listener to the download link. Something along the lines of ...
$('#my-download-link').click(function() {
setTimeout(function() {
window.location.href='myotherpage.html';
}, 1000);
});
The setTimeout is useful here to ensure the download has been triggered before redirecting.
I am assuming you are working jQuery and you are at a novice level. First, you begin with a document ready function, as always. Inside that you put your click listener, in this case "#navigation a" is the selector. Now whatever actions you need can go sequentially inside of this function. For example, below I am removing a class and then adding another one. But you can fire multiple clicks, cascade functions, whatever you want to do:
$(document).ready(function(){
$("#navigation a").click(function(event){
$("#navigation a").removeClass("selected");
$(this).addClass("selected");
// you could put function calls here
});
Notice how when you refer to your selector object a second time or more, you can use (this) as a ref. However, if your code gets more complex than this, you will want to learn a framework so that multiple things can be updated at once automatically, rather than manually firing individual function calls. Hope this helps.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
Background info:
I have a function that when called creates select list inside a form and populates it. After that the script runs through the options in the list and looks for a certain value. If the value is there, the script 'selects' that option.
Problem:
Because the list is dynamically created and is some times very large, it takes a while to load. When this happens, the second part of the script (the part that selects an option), does not do anything because the select list has not had time to load.
Idea for a solution:
What would be nice is to call the second part of the function (as a separate function) in an onload event for the select list. But select lists are not supposed to have an onload attribute. The other idea is to simply add a delay, but one day the delay may not be long enough.
How are you doing your AJAX call? Most AJAX libraries will provide the mechanism to do a callback on successful completion. For example in jQuery:
$("#myList").load("ajax.url", function(){
//your content has been loaded, so you can do your selection logic here
});
If you're handling the ajax response manually & building your list in javascript, then you're already have code that knows when the list is finished, so you can just do the selection part once that has finished rather than as a separate function (like as zyeming has suggested).
If that doesn't help you, it might be worth posting some code so people can give you a more specific answer.
Using a delay is not reliable. Whatever you're using to populate the select list should call the function directly when it is finished.
alternately:
Since there is no "onload" event for the select all you can really do it have a function that calls itself after a timeout. If the length of the items in the select list has changed from zero, you know something is currently adding items (the start-point). If the start-point has been reached and nothing has changed after the next timeout, you can assume items have stopped being added to the list, so you can then run the second function.
Why don't you make the function which selects option a callback function. It will be call at the end of the function which creates the list. E.g.
function createList(onComplete) {
// Create the list and maybe other tasks
onComplete();
}
Note: might not be like this but I think you've got the idea...
Ok, I have finally fixed the issue. The solution was completely different than what was discussed here. Basically, I was using 'new Option(value, text)' to add options to my list. I ended up throwing in a if statement and when a value equal what I needed is used new Option(value, text, true). and that solved the problem. All in a day's work.