I got some issue with useState and "if else" statement. I wanted to change displayed text with a click.
When I checking if counter icrement is working, it works, but when I add setText in "if else" statement there is a problem and just doesnt work properly. Icnrement strats to work strange when clicking and change a text is just imposible. Even in console increment looks wrong. Can someone help what I am doing wrong?
let counter = 0;
const [txt, setTxt] = useState("Text1");
const handleClick = (e) => {
if (
e.target.classList.contains("fa-angle-right") || e.target.classList.contains("fa-angle-left")
) {e.target.classList.contains("fa-angle-right") ? counter++ : counter--;
if (counter === 1) {
console.log(counter);
setTxt("Text2");
} else if (counter === 2) {
console.log(counter);
setTxt("Txt3")
} else if (counter > 2) {
counter = 0;
console.log(counter);
setTxt("Text1");
} else if (counter < 0) {
counter = 2;
console.log(counter);
setTxt("Text3");
} else if (counter === 0) {
console.log(counter);
setTxt("Txt1");
}
}
};
Every time setTxt('...') is executed, the component is re-rendered and the function executes again, so counter gets the value of 0.
If you want to preserve the value of your counter between renders, put it as a new state ( const [counter, setCounter] = useState(0) )
OK, #AdriánFernándezMartínez I did that way and its close. Just after first clik, in a first "if" (if (counter === 1)) console shows 0 and i have to click twice to chage it and change Txt (but is should be 1 after setCounter(counter + 1)). Next, in a third "if" (else if (counter > 2)) console shows 3 and again I need to click twice to change Txt (after 1st click its 0 and after 2nd it become 1). Still need help.
const [counter, setCounter] = useState(0);
const [txt, setTxt] = useState("Text1");
const handleClick = (e) => {
if (
e.target.classList.contains("fa-angle-right") ||
e.target.classList.contains("fa-angle-left")
) {
e.target.classList.contains("fa-angle-right")
? setCounter(counter + 1)
: setCounter(counter + 1);
console.log(counter);
if (counter === 1) {
console.log(counter);
setTxt("Text2");
} else if (counter === 2) {
console.log(counter);
setTxt("Text3");
} else if (counter > 2) {
setCounter(0);
console.log(counter);
setTxt("Text1");
} else if (counter < 0) {
setCounter(2);
console.log(counter);
setTxt("Text3");
} else if (counter === 0) {
console.log(counter);
setTxt("Text1");
}
}
};
Related
I want to make a code to assign logic input for my sheet. I use IF to make it. My code ran successfully but the logic didn't work. I have checked it many times, but I couldn't find something wrong. Can you help me with this? I'm stuck. Please review my example sheet and my script for more information. Thank you! https://docs.google.com/spreadsheets/d/1eV2SZ45Gs6jISgh_p6RIx-rfOGlHUM6vF114Mgf6c58/edit#gid=0
function logic(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var activeCell = ss.getActiveCell();
if (activeCell.getColumn() == 1 && activeCell.getRow() > 1 && ss.getSheetName() == "mama" && activeCell.getValue() == "Yes") {
activeCell.offset(0,1).clearContent();
activeCell.offset(0,1).setValue("1");
} if (activeCell.getColumn() == 1 && activeCell.getRow() > 1 && ss.getSheetName() == "mama" && activeCell.getValue() == "Hafl") {
activeCell.offset(0,1).clearContent();
activeCell.offset(0,1).setValue("1/2");
} if (activeCell.getColumn() == 1 && activeCell.getRow() > 1 && ss.getSheetName() == "mama" && activeCell.getValue() == "No") {
activeCell.offset(0,1).clearContent();
activeCell.offset(0,1).setValue(0);
}
}
You can simplify your code this way.
(Note that I use the const variable declaration instead of var (ES6 - V8 engine))
function logic() {
const ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const activeCell = ss.getActiveCell();
const activeCellValue = activeCell.getValue();
if (activeCell.getColumn() === 1 && activeCell.getRow() > 1 && ss.getSheetName() == "mama") {
switch(activeCellValue) {
case 'Yes':
activeCell.offset(0, 1).clearContent();
activeCell.offset(0, 1).setValue('1');
break;
case 'Half':
activeCell.offset(0, 1).clearContent();
activeCell.offset(0, 1).setValue('1/2');
break;
case 'No':
activeCell.offset(0, 1).clearContent();
activeCell.offset(0, 1).setValue('0');
break;
}
}
}
This way you only have to test the common conditions once.
Using the Switch function clearly shows the behavior of the script depending on the input value 'ActiveCellValue'.
If you need that only one action resolve per run, you need to use else if to chain the statements:
if(statement){
Action
}else if (statement2){
Action2
}else if...
if (value >= 2) {
return 1
} else if (value >= 1) {
return 0.9;
} else if (value >= 0.8) {
return 0.7
} else if (value >= 0.5) {
return 0.5;
} else {
return 0;
}
How to solve this if-else ladder. If i use switch cyclometric complexity increases and also also values feels like true.
In some cases the solution is breakaway code. Not everyone likes it - I do like it.
It just means you handle situations "from the top" and end situations with a return
pseudocode in any language...
(Everything should be in a function anyway...)
HandleTemperature(float t)
{
if (t > 90)
{
RunEmergencyCooling();
return;
}
if (round.t == 63)
{
DealWithgMagicValue();
return;
}
if (round.t > 40)
{
Debug.("normal temps! no worries!);
return;
}
// if you get to here, temp is very lopw
RunEmergencyHeating();
}
(In many languages there's a "finally" or "always do" concept, which can work well w/. breakaway dcode.)
Your example ...
Step 1, put in in a function as it should be anyway, Step 2 use "breakaway chunks".
float HandleValue(float v)
{
if (2.0 <= v) {
return 1
}
if (0.7 < v && v < 2.0) {
return 0.9;
}
if (0.13 <= v && v <= 0.7) {
return 17.6;
}
log didn't find a bracket in HandleValue
return default value
}
Every bracket is totally explicit. You can easily build testing code from there, too.
Those annoying long blocks before errors ...
Breakaway is particularly clean-looking in error cases...
Something()
{
if comms.text != 17.2
{
.. 100s of lines of code here ..
.. they are all indented ..
}
else
{
an error!
}
}
Some (but not all) believe this is better:
Something()
{
if comms.text == 17.2
{
an error!
return; .. note the "return" in breakaway code
}
.. 100s of lines of code here ..
.. no need for indentation ..
}
"Breakaway code" may work for you in some cases; in any event you can be aware of the approach.
class CoinData {
var _controller = StreamController<Map<String,dynamic>>();
.....
Stream<Map<String,dynamic>> getAllCurrentRates() {
int numAssets = 0;
int counter = 0;
this.listAllAssets()
.then((list) {
if (list != null) {
numAssets = list.length;
List<Map<String, dynamic>>.from(list)
.where((map) => map["type_is_crypto"] == 1)
.take(3)
.map((e) => e["asset_id"].toString())
.forEach((bitCoin) {
this.getCurrentRate(bitCoin)
.then((rate) => _controller.sink.add(Map<String,dynamic>.from(rate)))
.whenComplete(() {
if (++counter >= numAssets) _controller.close();
});
});
}
});
return _controller.stream;
}
.....
}
The length of returned list is around 2500 and this value is assumed by numAssets, however as you see that list is modified later and therefore its length is less, then the evaluation (++counter >= numAssets) is incorrect. So, is it possible to fix that code maintaining its current structure?
.take(3) is temporal, it shall be removed later.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
i'm a beginner at C++ and i tried to make a script for a Trinity Core World of Warcraft private server but it seems that some of the codes ran successfully and the others are escaped for unknown reason..
here's the code
#include "ScriptPCH.h"
#include "DisableMgr.h"
class LearnSpellsOnLevelUp : public PlayerScript
{
public:
LearnSpellsOnLevelUp()
: PlayerScript("LearnSpellsOnLevelUp"){};
void OnLevelChanged(Player* player, uint8 oldLevel)
{
if (player->getClass() == 3 && player->getLevel() >= 12) // ran
{
if (player->HasSpell(23356)) // ran
return; // ran
else // ran
player->LearnSpell(23356, false); // ran
player->GetSession()->SendAreaTriggerMessage("|cff00FF00You Learnt new Spell [Taming Lesson]!|r"); // ran
}
if (player->getClass() == 9) // Warlock // ran
{
if (player->getLevel() >= 2) // ran
{
if (player->HasSpell(44163)) // ran
return;
else
player->LearnSpell(44163, false); // ran
player->GetSession()->SendAreaTriggerMessage("|cff00FF00You Learnt new Spell [Summon Imp]!|r"); // ran
}
else if (player->getLevel() >= 10)
{
if (player->HasSpell(25112))
return;
else
player->LearnSpell(25112, false);
player->GetSession()->SendAreaTriggerMessage("|cff00FF00You Learnt new Spell [Summon Voidwalker]!|r");
}
else if (player->getLevel() >= 20)
{
if (player->HasSpell(712))
return;
else
player->LearnSpell(712, false);
player->GetSession()->SendAreaTriggerMessage("|cff00FF00You Learnt new Spell [Summon Succubus]!|r");
}
else if (player->getLevel() >= 30)
{
if (player->HasSpell(691))
return;
else
player->LearnSpell(691, false);
player->GetSession()->SendAreaTriggerMessage("|cff00FF00You Learnt new Spell [Summon Felhunter]!|r");
}
else
return;
}
}
};
void AddSC_LearnSpellsOnLevelUp()
{
new LearnSpellsOnLevelUp();
}
i wrote next to the codes that ran successfully // ran
Pay close attention to the order of your getLevel conditions.
if (player->getLevel() >= 2)
{
}
// Here, it's certain that the level is < 2, since it wasn't >= 2.
// Thus, none of these following tests will be true.
else if (player->getLevel() >= 10)
{
}
else if (player->getLevel() >= 20)
{
}
else if (player->getLevel() >= 30)
{
}
else
return;
You should test the levels starting with the greatest one and work your way donwnward.
if (player->getLevel() >= 30)
{
}
// The level is less than 30. Is it greater than 20?
else if (player->getLevel() >= 20)
{
}
// The level is less than 20. Is it greater than 10?
else if (player->getLevel() >= 10)
{
}
// The level is less than 10. Is it greater than 2?
else if (player->getLevel() >= 2)
{
}
else
return;
Looks like there is simply a logic bug. Let's look at this statement:
if (player->getLevel() >= 2) // ran - ok so far
And now a lot of this:
else if (player->getLevel() >= 10) - and others (comparing with 20, 30)
Now suppose your 'player' has 15 level - looks like the intent was to run the second if block (e.g. where you compare with >= 10)
But there is a problem: if the level is 15 then everytime only the first if-block is executed (because obviously 15 >= 2).
Solution: compare to range, like this:
if ((player->getLevel() >= 2) && (player->getLevel() < 10))
...
else if ((player->getLevel() >= 10) && (player->getLevel() < 20))
...
And so on.
I'm sure you've been there. You want to say "if flib do this, if flob do that, if flab do diet, etc" where any number of them can be true, then at the end you want an "if you didn't do ANY of them".
For example (the examples below are in Swift, as I've been playing with it, but I think the situation is the same in most languages):
let thing = 101
var isInteresting = false
if (thing % 3 == 0) {
println("\"\(thing)\" is a multiple of three.")
isInteresting = true
}
if (thing > 100) {
println("\"\(thing)\" is greater than one hundred.")
isInteresting = true
}
if (thing > 1000) {
println("\"\(thing)\" is greater than one thousand.")
isInteresting = true
}
if !isInteresting {
println("\"\(thing)\" is boring.")
}
I find keeping track of a boolean to tell me whether I did anything or not kinda ungainly.
The only other way I came up with was this:
let thing = 101
let isAMultipleOfThree = (thing % 3 == 0)
let isGreaterThan100 = (thing > 100)
let isGreaterThan1000 = (thing > 1000)
if isAMultipleOfThree {
println("\"\(thing)\" is a multiple of three.")
}
if isGreaterThan100 {
println("\"\(thing)\" is greater than one hundred.")
}
if isGreaterThan1000 {
println("\"\(thing)\" is greater than one thousand.")
}
if !(isAMultipleOfThree || isGreaterThan100 || isGreaterThan1000 ) {
println("\"\(thing)\" is boring.")
}
but if anything that's worse (if you add a new clause you need to remember to add it in three places.
So my question is, is there a neat, succinct way of doing this?
I'm dreaming of an imaginary switch-like statement:
switchif { //Would have fallthrough where every case condition is checked
case thing % 3 == 0:
println("\"\(thing)\" is a multiple of three.")
case thing >100 :
println("\"\(thing)\" is greater than one hundred.")
case thing > 1000:
println("\"\(thing)\" is greater than one thousand.")
none: //Unlike 'default' this would only occur if none of the above did
println("\"\(thing)\" is boring.")
}
It's a good question that does not have a perfect answer. However, here's one other idea in addition to those you suggest: Encapsulate the testing machinery in a procedure to allow the calling code at least to be a bit more streamlined.
Specifically, for your example, the calling code can be this:
if (! doInterestingStuff(101)) {
println("\"\(thing)\" is boring.");
}
If testing is encapsulated into a procedure:
public boolean doInterestingStuff(int thing) {
var isInteresting = false
if (thing % 3 == 0) {
println("\"\(thing)\" is a multiple of three.")
isInteresting = true
}
if (thing > 100) {
println("\"\(thing)\" is greater than one hundred.")
isInteresting = true
}
if (thing > 1000) {
println("\"\(thing)\" is greater than one thousand.")
isInteresting = true
}
return isInteresting
}
I'm not sure how you'd do this in Swift, but since you didn't give a language tag I'll answer in C++.
The key to this is that && is short circuiting, and the second part won't be evaluated when the first part is false. It's the same idea as your boolean flag, but it's a little more automated.
struct Tracker
{
Tracker() : any(false) { }
bool operator()() { any = true; return true; }
bool any;
};
int thing = 101;
Tracker tracker;
if (thing % 3 == 0 && tracker()) {
printf("\"%d\" is a multiple of three.\n", thing);
}
if (thing > 100 && tracker()) {
printf("\"%d\" is greater than one hundred.\n", thing);
}
if (thing > 1000 && tracker()) {
printf("\"%d\" is greater than one thousand.\n", thing);
}
if (!tracker.any) {
printf("\"%d\" is boring.\n", thing);
}
See it in action: http://ideone.com/6MQYY2
kjhughes' answer inspired me a little:
Perhaps one could write a global function that accepts an indeterminate number of key-value pairs (or even just two element arrays), where the key is a comparison and the value is the statement to run if it's true. Then return false if none of them were run, otherwise true.
Update:
Tried it, it's horrible!
//Function:
func ifNone(ifNoneFunc:()->Void, tests: Bool...)
{
var oneTestPassed = false
for test in tests
{
oneTestPassed |= test
}
if(!oneTestPassed)
{
ifNoneFunc()
}
}
//Example:
let thisThing = 7
ifNone(
{
println("\(thisThing) is boring")
},
{
if(thisThing % 10 == 0)
{
println("\"\(thisThing)\" is a multiple of 10")
return true
}
else
{
return false
}
}(),
{
if(thisThing % 3 == 0)
{
println("\"\(thisThing)\" is a multiple of 3")
return true
}
else
{
return false
}
}(),
{
if(thisThing > 1_000_000)
{
println("\"\(thisThing)\" is over a million!!")
return true
}
else
{
return false
}
}()
)