7 ms·
> Ultimately, React is f(newState) => UI. If that function isn't pure you're gonna have a bad time. React is not that at all. Unless your UI is very simple, Re
by petilon 4y ago
> Ultimately, React is f(newState) => UI. If that function isn't pure you're gonna have a bad time.
React is not that at all. Unless your UI is very simple, React is not f(newState) => UI. React isn't functional. More on that here: https://mckoder.medium.com/why-react-is-not-functional-b1ed12a41323 https://mckoder.medium.com/why-react-is-not-functional-b1ed1...
- quickthrower2 4y agoYou are both right. React components should render based on state that is managed by React, such that the rendered output changes only if the state changes. The complicated bit is the handling of events and changing the state. Hence why you get Redux for state but there is no “Redux for views”
- the_gipsy 4y agoReact very heavily pushes "component lifecycle" events, since it was class based up until now with hooks. That is, changing the state in the view function itself. It's not wrong, it gives you one kind of separation of concerns: components. But "the view is a function of state" is completely misleading IMO.
- treis 4y agosetState is a convoluted way of passing the newState to components. useEffect is a side effect and if you use it you're gonna have a bad time.
- petilon 4y ago> useEffect is a side effect and if you use it you're gonna have a bad time. Right.. but then you can't really use React for building serious UI.
- treis 4y agoFrom what I've seen that's like saying you need to use salt to be a good cook while pouring a bucketful on a salad. Perhaps it's technically true but from what I've seen you can build pretty complex UI without useEffect if you follow the rules.
- schwartzworld 4y agoYou have to use it, obviously, but it should be used for side effects primarily. A good indicator is if all the values in your dependency array are react props/state, you're doing it wrong.
- ojkelly 4y agoYou can build serious UI’s without useEffect. But it’s a powerful escape hatch like rust’s `unsafe` block. Rust can do amazing things to ensure safety of your program, but there’s still times where a human can do it better. By signposting that, keeping it to limited blocks, and wrapping it up in a safe function you get the capability to do hard things, while exposing a safer API. useEffect is similar, it lets you write the imperative synchronisation logic. For example if you need to interact with a DOM element that only has an imperative API, someone needs to do the work somewhere to wrap it in a declarative one. You can do that in a component with a useEffect hook, and then expose a declarative API.
- dsego 4y agoIt's still using the useEffect hook, but just wrapped in a useFetch or something. So technically you're not building a UI without useEffect, just hiding it, no?
- ojkelly 4y agoHow far down the rabbit hole do we need to go? Because at some point your function call is manipulating registers on the CPU. If we go even further, the CPU needs to load its next instructions and then the data required. Point being, we abstract and encapsulate complexity and provide a simpler API around it. It’s the only feasible way to manage the inherent complexity. React builds up a virtual description of UI. react-dom and react native take that description and synchronise it to the UI layer. If you need to do something extra, that they don’t handle like managing a map widget (ie mapbox) in React that only has an imperative API, it sure would be nice to do that yourself. You can build a UI without useEffect. You can hide messy implementation details inside a well tested component, and contain where useEffect is being used. And, you can understand how useEffect works so that you can use it without it having a negative effect on you.
- dsego 4y agoIt's just that "You can build a UI without useEffect." and "You can ... contain where useEffect is being used." are not the same statement. Maybe I'm being pedantic, but when I read "build without X", I think there is some method that can be used to avoid X, not that I can hide away X.
- yathaid 4y agoIf you need to fetch a piece of data when the component loads, how do you do it without useEffect?
- MrPatan 4y agoYou don't do that. Why would fetching data depend on whatever is being rendered? You know what data you need or not need before rendering anything, or you will be in a world of pain.
- yathaid 4y agoI am not sure I am following. Say your homepage has a link to a page that shows the top scorers in a league. Where/when does the fetching of the top scorers happen ?
- MrPatan 4y agoSure: - Click the link to show top scorers - Initiate fetching the data - (The view may change to indicate you're loading the top scorers, if you want, that's a different matter). - Receive the data, the view changes to display the data This is opposed to: - Click the link to show top scorers - View changes to show top scorers component. A component loads, or mounts, or inits, or does something which triggers a data fetch - Receive the data, the view changes to display the data Your app "knows" you need the data when the user clicks the link, no need to involve the view components into this. This gives you the ability of adding a lot of complexity to how you fetch the data that is best handled outside a UI component (like caching, reusing it in other components, error handling, retrying, throtling, whatever), while saving you from a whole class of problems where a misunderstood component lifecycle has consequences for your data. Frameworks like React or Angular are going to try to help you by caching outputs, reusing components, dropping updates for the same frame, prerendering, preloading or anything really. If you fetch data when a component does any of that, suddenly you have to care about it and fully understand it. The abstraction leaked. If you treat the component as close to a pure function as you can, things become much simpler. This applies to relatively big, relatively complicated apps, controlled by a single entity, where it pays off to prioritize simplicity.
- ojkelly 4y agoThe linked article doesn’t convince me, instead it shows a misunderstanding of react and hooks. > But then they added hooks and useState and useEffect and so on, which made the functions impure. The problem with hooks is that they “hook into” React state and lifecycle features, which means it is modifying global state. React components don’t update the dom every time they run, they update the fiber tree / virtual DOM. Only in the commit phase is the DOM updated and side-effects are run. My rough understanding is that: Hooks, excepting useEffect, all run in the render phase. UseState hooks store data in the component in the fiber tree, and capture a sequential list of updates when you call setState. Algebraic effects can seem a bit odd at first, but it’s really like a generalised try/catch. Instead of storing state in the function itself, you reach out up the stack to the component and store it there. And every hook you call from your hook stores it there too. It’s why call order is important, because it’s how they know which is which. You don’t modify any global state though. The actual component function needs to be able to be called multiple times in the render phase (which just updates the vdom), and must have the same output each time, if the inputs/props are the same. Every now and then, the tender phase can be interrupted to run the commit phase, which synchronously brakes a snapshot of the vdom and applies all the needed updates to the outside world. Perhaps it’s better to think of as render: f(props) -> descriptionOfUI commit: apply(descriptionOfUI) I would absolutely say components and hooks are functional, with algebraic effects. And that the resulting data struct from those components, is what’s used to produce side effects. Even useEffect, is a description of a side effect to run, it doesn’t run in your hook, it runs on commit with all the other side effects. There’s a ton of optimisations under the hood but that’s roughly my understanding of how it works.
- petilon 4y ago> ...and capture a sequential list of updates when you call setState. In functional programming, functions are not allowed to do that. The only thing a function is allowed to do is return a value. > ...you reach out up the stack to the component and store it there. FP functions are not allowed to do that. In FP functions can only rely on the parameters passed to it (it cannot refer to anything outside) and it should not do anything beyond return a value. > It’s why call order is important, because it’s how they know which is which In FP, functions can be called in any order (unless one function needs the return value of another), and the final result is not affected by the order. > You don’t modify any global state though. If you have state it is not FP, whether it is global or not.