2

I'm trying to add a whole array to the useState variable but I keep getting null, what the program is supposed to do is that first it checks to see if a default studio is available and add that to defaultStudioAvailable and then take that studio out from the studios array and then does another check on all the other studios and adds them to the others array with the line others[studio] = res; and adds that to state variable otherStudiosAvailable, however I get the correct details in the others array but nothing gets added to the otherStudiosAvailable state array,

can anyone see what I'm doing wrong? any help would be appreciated.

const Home = ({i18n}) => {

  const [defaultStudioAvailable, setDefaultStudioAvailable] = useState();
  const [otherStudiosAvailable, setOtherStudiosAvailable] = useState([]);

  const studios = ["de", "fr", "pl", "en", "nl", "ru"];
  const otherStudios = studios.filter(item => {
    return item !== i18n.language;
  });

 useEffect(() => {

 let others = [];

    checkForAvailableAgent(
      `sales_${i18n.language}`,
      "LinkToStudio",
      "ServiceID"
    )
      .then(res => {
        setDefaultStudioAvailable(res);
      })
      .catch(error => {
        console.log("an error happened.");
      });

   for (const studio of otherStudios) {
      checkForAvailableAgent(
        `sales_${studio}`,
        "LinkToStudio",
        "ServiceID"
      )
        .then(res => {
          // this has the correct values
          others[studio] = res;
          // this keeps being null even though others have values
          setOtherStudiosAvailable(others);
        })
        .catch(error => {
          console.log("an error happened.");
        });
    }

    console.log("others[studio]: ", others);
    console.log("other studios available: ", otherStudiosAvailable);
  }, [defaultStudioAvailable, i18n.language]);
}

// console output

others[studio]:  [en: false, fr: false, nl: false, pl: false, ru: false]

other studios available:  []




{defaultStudioAvailable ? (
        <Button
          variant="success"
          className="btn-xlarge"
          onClick={e => callBtnClick("direct")}
        >
          {t("callBtn")}
        </Button>
       ) : otherStudiosAvailable ? (
       <Button
          variant="success"
          className="btn-xlarge"
          onClick={e => callBtnClick("flag")}
        >
          Other studios available
        </Button>
      ) : (
    ""
  )}
akano1
  • 40,596
  • 19
  • 54
  • 67
  • Can you log the other studio available outside the `useEffect` mostly about return? – Ramesh Oct 11 '19 at 06:34
  • 1. Put your `console.log` statements inside the `then` callback because that is where you receive data. Outside then doesn't guarantees your promise was resolved. 2. `others` should be an object if you want to set key/values on it. Not an array. – Kushagra Gour Oct 11 '19 at 06:35
  • @akano1, check my answer – Dhananjai Pai Oct 11 '19 at 06:42
  • Check this answer https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately – Ramesh Oct 11 '19 at 06:46
  • Possible duplicate of [useState set method not reflecting change immediately](https://stackoverflow.com/questions/54069253/usestate-set-method-not-reflecting-change-immediately) – Ramesh Oct 11 '19 at 06:47

1 Answers1

1

the problem is the asynchronous nature of useState fns

You are console.log() inside the same useEffect() before the setState fn updates the value.

useEffect(() => {
 let others = [];
 checkForAvailableAgent(
      `sales_${i18n.language}`,
      "LinkToStudio",
      "ServiceID")
   .then(res => { setDefaultStudioAvailable(res); })
   .catch(error => { console.log("an error happened."); });

 for (const studio of otherStudios) {
   checkForAvailableAgent(
        `sales_${studio}`,
        "LinkToStudio",
        "ServiceID"
   )
   .then(res => {
       others[studio] = res; // here you are not using the updated value anywhere, so no problem here
      setOtherStudiosAvailable(others); // the asynchronous setState has been called, the callback can be obtained with a useEffect on the updated state value
   })
   .catch(error => {console.log("an error happened."); });
 }
    console.log("others[studio]: ", others); //using a local variable, should log fine
    console.log("other studios available: ", otherStudiosAvailable); // the otherStudiosAvailable has not been updated yet., uses the previous value []
  }, [defaultStudioAvailable, i18n.language]);
}

To get the value after it has been updated, useEffect on otherStudiosAvailable

useEffect(() => console.log(otherStudiosAvailable), [otherStudiosAvailable])

Update

Instead of the multiple conditional operators, it would be best to simplify the structure as

{defaultStudioAvailable && (
        <Button
          variant="success"
          className="btn-xlarge"
          onClick={e => callBtnClick("direct")}
        >
          {t("callBtn")}
        </Button>
       )}
{otherStudiosAvailable&& otherStudiosAvailable.length && ( //otherStudiosAvailable is an [] and always truthy
       <Button
          variant="success"
          className="btn-xlarge"
          onClick={e => callBtnClick("flag")}
        >
          Other studios available
        </Button>)}

In your code the otherStudiosAvailable was in the else part of the ternary operator, so even if it has values, it wont run if defaultStudioAvailable is truthy

Dhananjai Pai
  • 5,914
  • 1
  • 10
  • 25
  • thanks, that's correct, but I'm using the value to make layout changes, how should I do that, if I'm setting it in the first useEffect, the console.log was just to see the value, in the second useEffect I have the correct values, but for layout changes like {otherStudiosAvailable? do sth : do sth else}, how can I achieve that – akano1 Oct 11 '19 at 06:55
  • show the jsx where you are using it for layout, it should update automatically after the values are set. the second useEffect is not required and was only for you to confirm the values are indeed being updated the way you want – Dhananjai Pai Oct 11 '19 at 06:57
  • thanks for responding, one final question, how can I check that otherStudiosAvailable has at least one true value because it has to have one true in the array to meet the second condition. – akano1 Oct 11 '19 at 07:12
  • 1
    if it has a length > 0, it will have one value. check the code above. If you have specific condition for the value in the array to be truthy, include that as the next step of && before the button – Dhananjai Pai Oct 11 '19 at 07:12
  • feel free to upvote/accept the answer if it has helped solve the problem :) cheers, – Dhananjai Pai Oct 11 '19 at 07:13