Using cleanup function to store prev state feels diabolical
@kika74976 күн бұрын
its nice to see that we have gone from something simple like: prev = count++ to something like this, all because of the hidden react hooks/effects and render sequence.😜
@AngelzWrath116 күн бұрын
react-use doing it the wrong way at the end made me lose a lot of confidence in that library
@michaelns98875 күн бұрын
it is "the wrong way" because Theo said so?
@AngelzWrath115 күн бұрын
@@michaelns9887 No, it's just objectively wrong. The value returned from that previous hook is actually the current value, but the value is updated after the render. If any other state changes causing another render, you'd see it displaying the current value rather than the previous value.
@jakehobbs15 күн бұрын
i've had other issues w/ that library too. i reach for usehooks-ts first now.
@Unc35 күн бұрын
It works fine if you need to show the value. It doesn't if you need to use the value.
@krs_772 күн бұрын
I don't think we can say that it's objectively wrong, as it won't return the current value, but, on a given render, it will return the value "captured" during the last render. The consideration about any other state changing and causing the display of the current value, it's not a sign of it being broken, it's just due to the fact it's not meant to return the "last different" value, but the value from the last render, which can be equal to current one, if the last render hasn't changed it, but has set it to the same value. In fact, I've seen that they also have another hook, named usePreviousDistinct which takes that into account.
@h4ggs6 күн бұрын
It seems like count and previous count should be combined into one piece of useState. Isn't that a principle that I feel like I've heard Theo say before? Something like "if two pieces of state are always updated together, they should just be one piece of state".
@nwsome6 күн бұрын
Generally, yes. Doesn't really matter here though, since neither setter is exposed outside the hook and they are always batched anyway.
@SSpirite6 күн бұрын
yes. You can use useReducer for it.
@Emmanuel-lz4dc6 күн бұрын
This is the correct answer
@purpleboi-y8p6 күн бұрын
Remember, he used useEffect here while in his previous videos he was/is pushing for devs to not use the useEffect hook!
@benheidemann38365 күн бұрын
When you set state in a cleanup function, it will re-render twice in production, not just dev mode. This is because the order of events here is render (due to initial state change) -> cleanup (due to re-render) -> effect (due to render) -> render (due to state set in cleanup). This is not a good implementation of previous value because 1) as demonstrated, it’s hard to understand, even by experienced react devs like Theo, and 2) it causes multiple renders (not an issue in isolation but from experience this stuff piles up and can exacerbate other issues in the app). A much better approach would be to batch the state updates as others have suggested. Probably this is best done behind a well implemented abstraction to usePreviousState.
@DeyLakIT6 күн бұрын
That usePrevious hook is not meant to be used in render and there is nothing wrong about it. It's meant to be used to compare current prop value with the value from the previous rendering. It can be useful in more complex scenarios, where you should perform some side effect, when you detect a specific change in a prop. That's why is stopped working, when you added a second setState before the first one. There were actually 2 renders (may be batched), but only one useEffect run. So it's important that the useEffect you use should not have any dependencies, exactly like react-use did it. If you need to actually render the previous prop value, if think the provided example is fine. But I've never really needed it in my practice. I find the mental model for usePrevious as a value from previous render much more usefull.
@felipegustavo55316 күн бұрын
which use case you find to the usePrevious hook normally?
@DeyLakIT5 күн бұрын
@felipegustavo5531 to detect some transition states and perform effects. Like closing modal, when isOpen prop is changing from true to false. Or isLoading state changes. Also can be usefull in business logic, like "when user is changing this input to a specific value, you should do something". Usually, you combine this usePrevious hook with an actual state which is set in a side effect, caused by the detected transition state.
@DeyLakIT5 күн бұрын
@@felipegustavo5531 to detect some transition states and perform effects. Like closing modal, when isOpen prop is changing from true to false. Or isLoading state changes. Also can be usefull in business logic, like "when user is changing this input to a specific value, you should do something". Usually, you combine this usePrevious hook with an actual state which is set in a side effect, caused by the detected transition state.
@DeyLakIT5 күн бұрын
@@felipegustavo5531 to detect some transition states and perform effects. Like closing modal, when isOpen prop is changing from true to false. Or isLoading state changes. Also can be usefull in business logic, like "when user is changing this input to a specific value, you should do something". Usually, you combine this usePrevious hook with an actual state which is set in a side effect, caused by the detected transition state.
@DeyLakITКүн бұрын
@@felipegustavo5531 for example to detect some change in isOpen or isLoading state and perform a side-effect. The benefit of it is detecting the change in props immediately and not after a setState call, the means avoiding an additional rerender.
@dough-pizza6 күн бұрын
I just faced this ref issue and was hella confused and you upload this gem! Thanks Theo!
@priyanshshah69056 күн бұрын
my brain desoyred it self, but that explanation helped so thanks!!
@11WicToR116 күн бұрын
loving these types of videos where you explain some quirk of react ...keep em coming :)
@cooldotty6 күн бұрын
I feel like using a quirk that makes a set state not rerender is less intuitive, but hey, if you’re hiding it in a hook I don’t care as long as it works
@adityacapalasetty72324 күн бұрын
Yes Theo please make a comprehensive video on the render cycle of react it would be a great help.
@ryannathanwilson6 күн бұрын
setCount(p => { setPrev(p); return p + 1 });
@lucaswong986 күн бұрын
simple is the best
@titbarros6 күн бұрын
Exactly my first thought
@diegoarf_6 күн бұрын
Could this be done with previous as a ref? Or is it necessary for it to be a state if we want to use it on render
@ajaysihota22996 күн бұрын
Needs to be state to be reacty
@ryannathanwilson5 күн бұрын
@@diegoarf_ if you want to guarantee that the UI is always rendering the value (especially given that the component will evolve and other items will trigger rerenders) then state is best, though there may be cases where a ref would be fine.
@emmanuelxs61436 күн бұрын
Learnt so much about react rerender circle thanks 😊 And yeah a full break down is really needed 😅
@jamesgulland5 күн бұрын
Theo I would love to see a breakdown of the React rendering process, it’s something that still gives me headaches! Biggups
@lxn74045 күн бұрын
I'd love a full breakdown of react rendering process 👍
@tzuilee5885 күн бұрын
this is actually super helpful, clear explanation
@simboy5 күн бұрын
We need use state to have optional 1. Dependency argument like use effect 2. 2. A to function to run everytime time u call setState for any logic the need to happen 3. A way to rerender the progrmticly
@alejandroechavarria5395 күн бұрын
React docs invite to avoid useEffect unless it is necessary. useEffect is usually the cause of many bugs. The reason for that is that modern react is inspired by the functional programming paradigm which invite the avoidance of the effects. In this case, the most robust approach will be to put the setPrev in the click handler. This also will avoid two rerenders and it is a simper solution.
@sunny8k5 күн бұрын
There's been some convoluted frameworks, but React is still king for that. So much boilerplate and unintuitive and overly verbose setup to do anything. Reminds me of the JavaServer Faces days of needing to know the ins and outs of the entire lifecycle to do anything productive - which is a terrible sign. Really hoping another framework can dethrone React's strangehold on the professional frontend world.
@piaIy5 күн бұрын
There's a simpler solution for local state that doesn't depend on props (requires explicit type definitions in TS though): useReducer((state, current) => [state[1], current], [initialPrevious, initialCurrent]) It returns a [[previous, current], setCurrent] tuple.
@0815HansGans6 күн бұрын
function usePrevious(value: T) { const currentRef = useRef(value); const prevRef = useRef(value); if (currentRef.current !== value) { prevRef.current = currentRef.current; currentRef.current = value; } return prevRef.current; } How about this? Saves one render cycle.
@abuzain8596 күн бұрын
Your approach is amazing, but I like his approach because his code seems more readable to me. However, this is just my personal preference.
@bluecup256 күн бұрын
big brain
@piaIy5 күн бұрын
It's not allowed to write or read ref.current during rendering, except for initialization.
@bluecup255 күн бұрын
@@piaIy says who
@piaIy4 күн бұрын
@@bluecup25 the React docs
@SigmaTapion6 күн бұрын
I'm scared of switching over to react when I'm used to vue where I can just do a little watch and set the old value onto the prev value ref
@bishal_mishra995 күн бұрын
Vue is much more intuitive and I was thinking of same thing this morning 😂 - most companies should use vue seriously - front-end job market is bloated with react soydevs
@justindouglas36595 күн бұрын
No need to switch over if it's not required
@philo236 күн бұрын
I always end up having to lookup this pattern up when I need it, and the useRef way always felt wrong. I’d never even thought about using useEffect’s cleanup to do it instead, that definitely reads like a much more intuitive way to do it. Something tells me I’m gonna remember it for next time now!
@tabletuser1234 күн бұрын
thats why i stopped using react bruh too many sweats
@t4styycs6 күн бұрын
I mean in this case u could just derive the prev count state on each render no need for two useStates but for other useCases it is correct
@kristemmerman9215 күн бұрын
Love the Epic React ad!
@vvvvvvvvvwv5 күн бұрын
I would probably just create a useStateWithPrevious hook that just updates the prev value in the setter function. Relying on the framework to call things in a certain order seems unnecessary and harder to reason about. function useStateWithPrevious(value) { const [current, setCurrent] = React.useState(value); const [prev, setPrev] = React.useState(); const setter = (newValue) => { setPrev(current); setCurrent(newValue); }; return [current, prev, setter]; }
@tririfandani18766 күн бұрын
no need for useEffect & useRef const [[prevCount, count], setCount] = useState([0, 0]) setCount(([_prevCount, _count]) => [_count, count + 1])
@krisbude96076 күн бұрын
it is about showing the previous version of any state. ... in this example it is just a counter. But the state could be a word, and you also want to display the previous word for example. Then your solution does not work.
@diego-aquino6 күн бұрын
I believe it does work. You are essentially storing the previous and the current value in the same state and setting them together. Regardless of the data types or how the next value is created, you'll always have access to the previous value in the set function. In the word example, you could just return [previousWord, newWord] from the set function, no matter where newWord comes from.
@agent.whiskeyy6 күн бұрын
This is the same as donig it "the boring way" aka storing an extra state just here u store it in an array of 1 state instead of 2 states, just over complicated for no reason
@krisbude96076 күн бұрын
@ you’re right… I read it wrong 😊
@ThugLifeModafocah6 күн бұрын
@@agent.whiskeyy no, it's not. With this approach you have less rerendering because you don't need another one for previous being changed. You have only one that handles both.
@ShinigamiZone5 күн бұрын
I really like watch in Vue (not watchEffect). Is there something similar in React?
@freedomowologba29006 күн бұрын
React has a useDeferredValue hook already. No need for the long walk around.
@zeroliuxiyuan6 күн бұрын
usehooks's implementation sets state directly in the render function. This feels off to me...
@vvvvvvvvvwv5 күн бұрын
It's totally fine. You often don't need effects. Search for "You Might Not Need an Effect", there's a page for this in the React docs.
5 күн бұрын
“Keep in mind that useRef doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render”
@simboy5 күн бұрын
Which is a feature
@abdelazizlaissaoui90796 күн бұрын
Yo7 should post a video about that React rendering process
@cristianmargineanu14585 күн бұрын
YOOO im crying right here, ive been doing this for at least 2 years and i work in a factory 😂
@additionaddict55246 күн бұрын
fyi, the epic web bundle, not much more, includes epic react. kinda crazy that the site doesn't show this
@farzadmf6 күн бұрын
Please do a video of the rendering process 🙏
@byShameless6 күн бұрын
Would running the code that uses the previous value inside the the setState be bad? If so can someone explain? example: setState((prev) => { *code with prev value*; return *new state*; })
@dave60126 күн бұрын
First Bender, then Flexo, then Fry.
@rajikkali23815 күн бұрын
I'll say it again. Just use Nuxt or Vue because it truly is "The inuitive framework"
@bubkabu3 күн бұрын
which editor is that?
@KopoLPedov4 күн бұрын
just use single state for current and prev value or better - use class components
@edwardallenthree5 күн бұрын
Helpful video.
@LA-fb9bf5 күн бұрын
What is vue.js doing here?
@O_Eduardo4 күн бұрын
This is one of the reasons I’ve never liked React. Honestly, I wasn’t a fan of its design from the very beginning. I’m eagerly waiting for better solutions to gain more traction-it feels like React’s time has passed. It hasn’t aged well. React developers might stick with it for so long they’ll never realize they didn’t need to go through all this complexity.
@roguesherlock6 күн бұрын
I usually just have an array to keep track of current and previous, ```tsx export default function usePrevious(current: T) { const [state, setState] = useState([null, current]) // [prev, current] if (state[1] !== current) { setState([state[1] ?? null, current]) } return state[0] } ```
@yanidoesit5 күн бұрын
You might like React as a developer but I fricken hate it as a user living on an island where 4G with congestion is as good as it get. Have you seen how Facebook or React app work when you have a crappy internet connection? It's hell! It times out before hydration is complete. Or even just fails to hydrate even the top post. What makes it easy for developers isn't always a solution users like.
@dbarnesdigital5 күн бұрын
Hydration is terrible. If a framework uses hydration they blew it.
@iamNATFAN3 күн бұрын
honestly, this video just turns me off react more. why do i need to learn all of this (seemingly) arbitrary framework logic in order to not footgun myself. at least with vanilla js and regular dom updates, you know what you're getting imo
@FatahChan6 күн бұрын
I got featured in a theo video
@polski0035 күн бұрын
Nice
@codedusting6 күн бұрын
reactnode 19 nextjs 15 failing during build because of some type error in react node. Also doesn't recognise the async components
@kingsleykelechionwuchekwa75086 күн бұрын
feels good to be first
@cherishkansara78516 күн бұрын
Yup
@shwinm6 күн бұрын
Is this not an extremely obvious case for useReducer???