2

How do I use prevState with useEffect in a functional component? I was told to update class component to functional component and I'm stuck in the componentDidUpdate part where prevState was used

 componentDidUpdate(prevProps, prevState) {
    if (prevState.search !== this.state.search) {
      this.getData()
    }
    if (prevState.finalSearch !== this.state.finalSearch) {
      if (this.state.finalSearch) {
        this.newData()
      } else {
        this.getRawData()
      }
    }
  }
 

<Search
          search={search}
          finalSearch={finalSearch}
        />
reactRookie
  • 189
  • 1
  • 9
  • Could you post more of your code and clarify a bit? It is difficult to tell what your problem is or what you are asking exactly. Typically if you are using `useEffect` you are not using `componentDidUpdate` so am a bit confused by your question. – otw Jul 04 '20 at 19:19
  • I was told to update a class component to functional component and there was this componentDidUpdate in the code and I don't how to change it to useEffect @otw – reactRookie Jul 04 '20 at 19:20
  • Does [this](https://stackoverflow.com/questions/53446020/how-to-compare-oldvalues-and-newvalues-on-react-hooks-useeffect) answer your question? – hotpink Jul 04 '20 at 19:21
  • Also look at the [React docs](https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state) – hotpink Jul 04 '20 at 19:22

4 Answers4

4

So it looks like you are just using previous state just to avoid unnecessary renders here. This was actually a common enough it was built into useEffect:

componentDidUpdate(prevProps, prevState) {
  if (prevState.count !== this.state.count) {
    document.title = `You clicked ${this.state.count} times`;
  }
}

Becomes:

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes

Source: https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects

Your component might look something like:

useEffect(() => {
  getData()
  
  if (finalSearch) {
    newData()
  } else {
    getRawData()
  }
}, [search, finalSearch]);
otw
  • 630
  • 4
  • 13
  • https://codesandbox.io/s/serene-sun-xuxq6?file=/src/App.js this is what I made till now. can you look at it once and say what's wrong? – reactRookie Jul 04 '20 at 19:36
  • 1
    @reactRookie What do you mean by what's wrong? You mean why it is not rendering? I don't really see the code from your question in here. – otw Jul 04 '20 at 19:42
  • oops sorry, I forgot to save the changes. it says there's no return statement but it's there. also the prevState thing starts from the line 96 – reactRookie Jul 04 '20 at 19:46
  • 1
    @reactRookie I am seeing `/src/App.js: Unexpected token (159:0)` – otw Jul 04 '20 at 19:49
  • 1
    @reactRookie I updated my answer to have what I think your component should look like. You shouldn't need `usePrevious`. – otw Jul 04 '20 at 19:51
  • 1
    @reactRookie functions being underlined is just your compiler telling you there is an error. If you mouse over it, it will tell you why. It seems like there are quite a lot of different issues in that code. – otw Jul 04 '20 at 20:47
  • Yeah I fixed it but the useEffect is giving problems, other errors are gone. when I click on a search result, nothing happens – reactRookie Jul 04 '20 at 20:52
  • 1
    @reactRookie When I type something in it seems to be working just fine when you select a result. If you are saying you see nothing when you just click and select a result, it doesn't look like your blur function is modifying any state. – otw Jul 04 '20 at 21:14
  • yeah I was editing it simultaneouly so was getting rid of all the bugs one by one. Now there's this new problem where with every keystroke, the api gets called and making the website slow. Maybe it's because of the useEffect. Can you have a look ? – reactRookie Jul 04 '20 at 21:17
  • 1
    @reactRookie I think we've solved your original question. We are getting into generally debugging of your app now. I'd appreciate it if you could just accept an answer here and post new questions as needed. – otw Jul 04 '20 at 21:23
  • Yeah sorry, I forgot to do that. the new question can be found here https://stackoverflow.com/questions/62734546/api-call-with-every-key-stroke – reactRookie Jul 04 '20 at 21:25
2

You have to create your custom hook usePrevious, refer this: here.

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
     ref.current = value;
  });
  return ref.current;
}

Then you have to do this way:

const Component = (props) => {
   const {search, setSearch} = useState('');
   const prevSearch = usePrevious({search, setSearch});
   useEffect(() => {
      if(prevSearch.search !== search) {
          //Your code goes here
      }
   }, [search])
}
Darsh Shah
  • 351
  • 3
  • 9
  • 1
    So since they are only using the previous values to detect if a render is needed, you don't need a custom hook, this is built into `useEffect`: https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects – otw Jul 04 '20 at 19:52
  • @otw yes, for this particular case we can use `useEffect` hook. But, if we want to use `prevState` value (for example we have a checkbox and depending on previous value, we need to change it), then the above mentioned way will resolve that issue in particular. Thus depending on situation, we can look for the best approach and apply that for resolving it. – Darsh Shah Jul 05 '20 at 08:12
0

You don't have prevState like in class lifecycle components but I think the answer here might help you, just instead for props make it for state

How to compare oldValues and newValues on React Hooks useEffect?

enter image description here

0

Simply use this

onClick={()=>setShowSearchInput(prevState=>!prevState)}
Deepak Singh
  • 749
  • 4
  • 16