Search code examples
reactjsloopsreact-hookssetstate

Have refreshed state in Hook in loop


Replacing the phrase - based on start and end index - by visibleText.

The problem - there is multiple phrases(each phrase changing per iteration) . So the value of transformedText is not refreshing by setTransformedText hook.

How to have changed transformedText - after setTransformedText - in each iteration?

for(const i in phrasesByCategory){

  const startIndex = phrasesByCategory[i].start_char;
  const endIndex = phrasesByCategory[i].end_char;
  const hiddenText = transformedText.substring(startIndex, endIndex);
  const visibleText = text.substring(startIndex, endIndex)

  const replacedPhrase  = replaceAt(transformedText, hiddenText, visibleText, startIndex, endIndex)

  setTransformedText(replacedPhrase)
}

The hook is string:

  const [transformedText, setTransformedText] = useState("")

It's replace the first iteration:

  const makeVisible = (phrasesByCategory) => {

    let currentText = transformedText
    setTransformedText((transformedText)=> {
      for(const i in phrasesByCategory){
        const startIndex = phrasesByCategory[i].start_char;
        const endIndex = phrasesByCategory[i].end_char;
        const hiddenText = transformedText.substring(startIndex, endIndex);
        const visibleText = text.substring(startIndex, endIndex);
        const replacedPhrase  = replaceAt(transformedText, hiddenText, visibleText, startIndex, endIndex)
        currentText = replacedPhrase
      }
      return currentText;
  })
}

Edit current solution - which finally anonymyse and unanomyse that phrases:

  const anonymyseByCategory = (phrasesByCategory, visible) => {
    const textArray = [transformedText];
    for (const i in phrasesByCategory) {
      const startIndex = phrasesByCategory[i].start_char;
      const endIndex = phrasesByCategory[i].end_char;
      let hiddenText = visible
        ? textArray[i].substring(startIndex, endIndex)
        : textArray[i].substring(startIndex, endIndex).replace(textArray[i].substring(startIndex, endIndex), 'X'.repeat(textArray[i].substring(startIndex, endIndex).length))
      const visibleText = text.substring(startIndex, endIndex);
      const sentenceWithReplacedPhrases = visible
        ? replaceAt(textArray[i], hiddenText, visibleText, startIndex, endIndex)
        : replaceAt(textArray[i], visibleText, hiddenText, startIndex, endIndex)
      textArray.push(sentenceWithReplacedPhrases)
      setTransformedText(sentenceWithReplacedPhrases);
    }
  }

Solution

  • I guess you have something like:

    let [transformedText, setTransformedText] = useState('Hello World');
    

    Since you are using the previous value of a state property (transformedText) in order to update it, you have to call your state property setter (setTransformedText) with a callback.

    setTransformedText((transformedText)=> {
        var hiddenText = ...;
        var visibleText = ...;
        var replacedPhrase = replaceAt(...);
        return replacedPhrase;
    });
    

    This is due to the fact that, state updates may be asynchronous in React.