Тёмный

React Compiler: It's Stranger Than You Think 

Theo - t3․gg
Подписаться 308 тыс.
Просмотров 34 тыс.
50% 1

I hope we don't "forget" this history of React Compiler now that it's here. It's been a wild journey, and I'm thankful Dan took the time to share so much from it
SOURCE
x.com/dan_abramov2/status/179...
Check out my Twitch, Twitter, Discord more at t3.gg
S/O Ph4se0n3 for the awesome edit 🙏

Наука

Опубликовано:

 

7 июн 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 145   
@ToroidalFoxCasual
@ToroidalFoxCasual Месяц назад
I really don't know Theo that much, but he keeps saying things like "rust is bad when you have to change stuff often". But I haven't seen him doing any rust project that requires huge refactors. How does he know that rust is bad for it? Also feels like refactorability is a function of time and scale than a language choice.
@kasper_573
@kasper_573 Месяц назад
At best, influencers are delusional and overrestimate their abilities. They believe their small focus area of actual skill can be translated into anything adjacent, which is what leads to them confidently spewing nonsense. At worst, it’s intentional and you’ve got yourself a charlatan. It’s a tale as old as any. I’m not sure where to place Theo, but he sure strikes me as a confident talker more than a skilled doer.
@TheTmLev
@TheTmLev Месяц назад
This is such an underrated comment. I've been writing Rust for 4+ years and it's such a productive language to work with. I don't deal with memory management, I rarely (once in a month) use explicit lifetimes, I can do a large refactoring in under one hour without any debugging because if "it compiles, it works". Yeah, I can spend one or two minutes more writing code before running it, but I don't need three hours of debugging after like in dynamically typed languages. Also, having used `sqlx::query!()` for querying your database and knowing that compiler can verify your raw SQL queries makes you hurt so much when you look at TypeScript alternatives like Drizzle/Kysely/what-have-you. Rust lets me not think about anything because the compiler will have my back. You just write a lot of code, and then the compiler helps you make it right.
@TheTmLev
@TheTmLev Месяц назад
This is such an underrated comment. I've been writing Rust for 4+ years and it's such a productive language to work with. I don't deal with memory management, I rarely (once in a month) use explicit lifetimes, I can do a large refactoring in under one hour without any debugging because if "it compiles, it works". Yeah, I can spend one or two minutes more writing code before running it, but I don't need three hours of debugging after like in dynamically typed languages. Also, having used sqlx::query!() for querying your database and knowing that compiler can verify your raw SQL queries makes you hurt so much when you look at TypeScript alternatives like Drizzle/Kysely/what-have-you. Rust lets me not think about anything because the compiler will have my back. You just write a lot of code, and then the compiler helps you make it right.
@TheTmLev
@TheTmLev Месяц назад
This is such an underrated comment. I've been writing Rust for 4+ years and it's such a productive language to work with. I don't deal with memory management, I rarely (once in a month) use explicit lifetimes, I can do a large refactoring in under one hour without any debugging because if "it compiles, it works". Yeah, I can spend one or two minutes more writing code before running it, but I don't need three hours of debugging after like in dynamically typed languages. Also, having used sqlx::query!() for querying your database and knowing that compiler can verify your raw SQL queries makes you hurt so much when you look at TypeScript alternatives like Drizzle/Kysely/what-have-you. Rust lets me not think about anything because the compiler will have my back. You just write a lot of code, and then the compiler helps you make it right.
@TheTmLev
@TheTmLev Месяц назад
This is such an underrated comment. I've been writing Rust for 4+ years and it's such a productive language to work with. I don't deal with memory management, I rarely (once in a month) use explicit lifetimes, I can do a large refactoring in under one hour without any debugging because if "it compiles, it works". Yeah, I can spend one or two minutes more writing code before running it, but I don't need three hours of debugging after like in dynamically typed languages. Also, having used sqlx::query!() for querying your database and knowing that compiler can verify your raw SQL queries makes you hurt so much when you look at TypeScript alternatives like Drizzle/Kysely/what-have-you. Rust lets me not think about anything because the compiler will have my back. You just write a lot of code, and then the compiler helps you make it right.
@omarshref4803
@omarshref4803 Месяц назад
You can easily put .reverse() after the .map() not before so it will just reverse the array of child components not the data array
@jacoblockwood4034
@jacoblockwood4034 Месяц назад
This is very true though many people might not realize that because a lot of newer JS devs especially might not realize that when you .map() returning JSX components, that's still just an ordinary array you can keep doing operations on. There is also Array#toReversed() but only 90% of users have support for it in 2024. Anyway doing .reverse after .map is of course better.
@cadekachelmeier7251
@cadekachelmeier7251 Месяц назад
There's also toReversed() now that you can use.
@JakobRossner-qj1wo
@JakobRossner-qj1wo Месяц назад
It is an quick example, everyone got what he is saying
@PhilipAlexanderHassialis
@PhilipAlexanderHassialis Месяц назад
Theo, we may have our differences on opinions but for this I need to take a stance: there is a reason why the core stuff of any big/critical application is written in C/C++/Rust/what-have-you. Because you need that peak performance - and you have the scores of developers to be able to re-write the whole thing, even from scratch if necessary. I understand where you come from and I get the "but we are in the move-fast-break-things phase" mentality. Nonetheless, the endgame is *AND ALWAYS WILL BE* to reach the performance that only pedal-to-the-metal gives. Go or Node or whatnot will never get to that point - and that's a good thing! But please, for the love of all that's holy, for once, make a video or something coming from the other viewpoint. Not every developer will work on the "move-fast-break-things". Not every developer will want to stay there. Many developer's careers will take them to the mythical lands of big corporations who write enterprise code - and there, every picosecond is worth millions. So please, for once, make a video coming from the other viewpoint. From the big-business/mission-critical/enterprise software. Just for once.
@shapelessed
@shapelessed Месяц назад
Honestly I also found his take on it quite shortsighted. It's nice to make a working prototype in a high-level language and achieve decent results. Heck, I even wrote a filesystem in TypeScript and Node, and the thing reached like 300MB sequential reads while using linked-lists as the data structure, which is already impressive, but this was just a fun side project to learn some things. For peak performance native modules would be a no-brainer, and eventually with moving technology and user expectations everybody is gonna have to result to nasty hacks or just go lower level, whether it is on the frontend or (especially) the backend. It sure can be a pain to introduce big changes in languages as stiff as Rust, but at the same time, that pain can quite often be offset by how the costs of operating the software go down, simply because your code runs faster and requires smaller infrastructure.
@Frostbytedigital
@Frostbytedigital Месяц назад
I work for big business and everything I do is considered a 'scrappy tool' it's almost always written in typescript and is a multi million dollar stop gap for the enterprise product written by a giant team. I've been doing it 5 years and 90% of my products have never got replaced because the teams cost more than we could ever save by rewriting a product that's 'poor performance' isn't really costing us anything (many things have a large enough sla window we're not worried about nanoseconds)
@voidmind
@voidmind Месяц назад
I agree with most of the things you said, except the bit about Go. Esbuild is written in Go, and it's blazingly fast.
@shapelessed
@shapelessed Месяц назад
@@Frostbytedigital Sure, but there are certainly cases where a difference between things like Node and Rust can easily amount to millions.
@Frostbytedigital
@Frostbytedigital Месяц назад
​@shapelessed Absolutely. I wouldn't do anything time sensitive, especially anything with ms or less accuracy needed, in Typescript(runtime is actually typically the browser or bun in my case). But acting like there isn't plenty of good reasons to write a quick and dirty ts product as a first step in big business is a little misleading. there's plenty of things interacting with millions in daily revenue that run off excel helper files to this day. The thing that saves the most money is the thing that exists and works. performance especially if it takes you significantly longer to acquire or more engineers to produce could cost more overall.
@tarasturchenko4528
@tarasturchenko4528 Месяц назад
Specifying deps manually is insane. I always have hated react for that. Also using immutable data seems nice at first look but later it brings a lot of complexity when your app scales
@jaredsmith5826
@jaredsmith5826 Месяц назад
I'm still experimenting with what React Compiler does to bundle size before I commit. I would love to see the team add some optimization level flags (a la gcc and clang) with some heuristics about trading off memoization against code size inflation. They'll probably just say to use Lazy and Suspense, as if the whole point of having the compiler wasn't to *not* have to rewrite your app, but I can dream.
@primostasis
@primostasis Месяц назад
react compiler + million js? is that possible?
@Supergeckos1000
@Supergeckos1000 Месяц назад
13:57 It's not *React* in a traditional sense. There's no inherent idea of reactivity in JavaScript. And it's pretty ridiculous to keep hearing that "React is just traditional JavaScript", but something like Solid isn't. Solid is just reactive programming, which in itself is older than React. Heck, you can run Solid signal code without components and it will still work, because it is just rather simple reactive primitives. Also, "data" is not reassigned. And I wouldn't expect code to rerun when data is reassigned. That is wrong terminology, especially because "data" is set as const. Using setState is not re-assignment. Only because setState hooks into the React renderer, does the code run as expected. And in that regard Solid actually behaves more like traditional JavaScript, where you setup subscribers and expect those to rerun when calling a signal setter.
@jacoblockwood4034
@jacoblockwood4034 Месяц назад
I don't think anybody is saying that Solid isn't just JavaScript, that point is more so in comparison to Svelte and to an extent Vue EDIT: I hadn't watched the video fully when I commented, that's really surprising I don't know why he said it like that
@TurtleKwitty
@TurtleKwitty Месяц назад
It's absoluely insane to hear people claim that js doesnt have an inherent idea of reactivity when the entire point of JS was to be reactive to elements in the HTML... I don't know what js you and Theo are using but it sure as fuck isnt the one in reality
@gageracer
@gageracer Месяц назад
Yeah, it's a weird af response to prove your point: React is REAL JS!11!!1! What do you think rest is, witchcraft running on the browser?
@Supergeckos1000
@Supergeckos1000 Месяц назад
@@TurtleKwitty It's not in the sense of value binding or reactive programming. Compare JS in the browser to something like WPF where you can directly bind C# values into your XAML markup...
@TurtleKwitty
@TurtleKwitty Месяц назад
@@Supergeckos1000 Are you really trying to say that binding your Js directly in html markup is not the same as binding your c# to XML? You can't actually be serious
@JLarky
@JLarky Месяц назад
In an ideal world, do you mean when using Flow?
@shapelessed
@shapelessed Месяц назад
If they had a compiler before they introduced hooks, then hooks suddenly turn into an even bigger abomination in my eyes. It isn't for no reason so many people hate on React. Part of it is JSX, but the bigger part is the use of hooks that quite literally come and go every few versions and blow your whole leg off when what they promised was joy of use and at most a light bullet hole. If they went deeper into the compiler route, it would have enabled React to have a WAY better DX than the today's versions.
@SirCorrino
@SirCorrino Месяц назад
About the Readonly thing, the team building the common components at my job mark all props as Readonly. I never really understood why since why would you want to change these things anyway? As for not changing the data for sorting, we usually slice the array. Not sure how that compares to spreading it performance-wise, though.
@kamalkamals
@kamalkamals Месяц назад
before i remember reactjs developers refuse sveltejs because they cannot trust to compiler sveltejs and they cannot understand how compile code js, but now they accept reactjs compiler, really bizard,
@elvispalace
@elvispalace Месяц назад
react dev refuse svelte because Reactjs is fine for react devs
@kamalkamals
@kamalkamals Месяц назад
@@elvispalace is fine technically or just feeling !!!
@jarrodhroberson
@jarrodhroberson Месяц назад
rust is not “bad” when you need to change it any more than any other language at a given scale (loc) appropriate to the language if the application is written naively. 20k of JS, Python or any other dynamic typed language is “bad” if you need to change it even when a skilled person wrote it initially
@anon_y_mousse
@anon_y_mousse Месяц назад
I'd never heard of HIR before, but after a quick search I suppose it makes sense as a buzz term for a transpiler. I would've just called it IR instead of trying to confuse people, because it doesn't matter how high or low it is, it's still an IR. Of course, I also didn't know that React had a compiler they were working on and now I have to go read it.
@dezyhe
@dezyhe Месяц назад
Personally, I like seeing HIR rather than IR. HIR signifies it's fairly close to an AST built from the source code plus some de-sugaring for simplification. Another reason is it's also possible to have multiple IR forms which make different tasks easier. Looking at Rust as an example, it has a HIR like the react compiler, but also a MIR which is what the type checker and borrow checking use.
@simonhartley9158
@simonhartley9158 Месяц назад
I don't understand the characterization of "not JavaScript" when code isn't re-run when data is reassigned. That seems React-brained because JS isn't reactive in that way. It does seem to highlight that React is a framework and not a library, since it's calling your code, rather than the other way around.
@CottidaeSEA
@CottidaeSEA Месяц назад
React is a library for state management and really only does proxying with their own event listener system. So it's a library and not a framework.
@simonhartley9158
@simonhartley9158 Месяц назад
@@CottidaeSEA The fact that it uses event listeners seems to be an implementation detail. Ultimately it calls render, not you, but I can see there's an argument that a library can be inverted that way.
@CottidaeSEA
@CottidaeSEA Месяц назад
@@simonhartley9158 You're still the one who tells it what to run, React just handles the "when" part of it since it is proxying all values you send to it. If you were to just use the regular JavaScript proxy with some convenience functions in a module you can quite easily create a rudimentary version of React. That's basically why I say it's a library and not a framework. It doesn't have the bells and whistles necessary to be a framework. Oh, and regarding the rendering, you can have components that don't render. One such example I have is for translation. I have a top level TranslationProvider which does all of the things related to the translations. However, we fetch and persist the locale to the Redux state. Because of that I simply wrapped the Provider for Redux, added a logic component inside of the Provider that just sends the locale up to the TranslationContext. So logic components are very useful for decoupling libraries when you are able to use contexts. It's also really useful when you're creating a game using React, but there's not many people who make games with React.
@Kaczucha888
@Kaczucha888 Месяц назад
I wanted to write the same thing! Solid model of data flow is much more JS than react triggering renders like whatever anything changes. Especially when we will probably have signals in JS as part of the TC39 standard
@CottidaeSEA
@CottidaeSEA Месяц назад
@@simonhartley9158 Huh... I wrote a reply that seems to have been yeeted and deleted by RU-vid, rude. Short version is that React doesn't have the bells and whistles necessary to be called a framework. If comparing it to operating systems, Windows would be a framework and React would be a DLL file the operating system uses.
@Holobrine
@Holobrine Месяц назад
14:00 In traditional JS, I expect the log to run once if it’s called once. The Solid way, and also my favored Svelte 5 way, make it clear that you are establishing a declarative binding and not making a simple procedural function call.
@gageracer
@gageracer Месяц назад
I want to see some benchmarks with compiler as people keep saying your code will be faster but it's doing 100% same optimizations you would do with memoization so technically there shouldn't be any hidden performance up. krausest's benchmark list has 20 react examples but none says anything about compiler(as they are all v18) but I assume most of them use the same memoizations and more optimizations like using signal solutions etc. If anyone have a data to show this actually improves performance that gets react closer to vue-solid-svelte level I would be really happy.
@voidmind
@voidmind Месяц назад
9:13 YES! I have had so many issues with devs ignoring the React rules and arguing that it still works, and no matter how much I try to explain that it will blow up in their face in unexpected and hard to debug ways, I keep seeing it in their code. I'm going to love that compiler doing those code reviews for me.
@user-up8fm3vb1r
@user-up8fm3vb1r Месяц назад
I was doubtful of my compiler nerdness but yes I like the fact I am a compiler nerd now
@pencilcheck
@pencilcheck Месяц назад
Haven't watched the video but doesn't matter what language, if you have to change often it just means the client or PM is bad (or perhaps is good because client is asking for a lot of features and you are raking in the money that way). The question isn't how many changes, but what changes are there. A lot of changes are simple to make, some changes are hard. Of course this is all relative to the language. With strong typing and a lot of restrictions I can see why Theo said the things he said. I would say that everyone is different, some people are just better at changing a lot of typing and a lot of structures very quickly. But it also might not be readable to other engineers either so the process will take longer.
@noahwinslow3252
@noahwinslow3252 Месяц назад
If I'm not mistaken, you don't need the For or Show components in solid, they're there for even better performance, they effectively replace keys in react
@johannesloher2817
@johannesloher2817 14 дней назад
Thats wrong, you need them. The reason is that your component function only runs once (when it is initially rendered). So if you just use a regular if statement, to do an early return similar, that code is never rerun, even when props/state change. You _need_ to explicitly bind something to the props/signals, in order to get reactivity. That’s what these helper components do.
@noahwinslow3252
@noahwinslow3252 14 дней назад
@@johannesloher2817 No, you can use ternaries. If statements probably won't work like you say, but the Solid compiler can process ternaries
@shapelessed
@shapelessed Месяц назад
7:35 - No. This is not the "only way to do this code safe". Just map the thing before you reverse. Map already produces a modified copy of the source array. Problem solved. Your example, my friend, was actually quite terrible.
@johannesloher2817
@johannesloher2817 14 дней назад
The point is not that you cannot solve the problem easily. The point is that it’s easy to get it wrong by accident.
@tarasturchenko4528
@tarasturchenko4528 Месяц назад
So after all this years react eventually bring caching to components as it should be
@sohrb
@sohrb Месяц назад
one thing I can't get out of my mind is why this compiler exists is it because we the developers suck at react or because of a bad dx or maybe both
@andreilucasgoncalves1416
@andreilucasgoncalves1416 Месяц назад
Probably to improve the react reputation because there are many devs who do not use react afraid of performance issues, and for projects with many layers of useContext the compiler will improve performance significantly when you update some of the providers
@pulasthibandara
@pulasthibandara Месяц назад
At 14:00, this video conviced me to checkout Solid, looks clean.
@tarasturchenko4528
@tarasturchenko4528 Месяц назад
I was really shocked when i did learn that react didnt cache your components by default and don’t have any adequate methods to cache data. In terms of DX vue is SO MUCH better than react that’s just insane
@tarasturchenko4528
@tarasturchenko4528 Месяц назад
Like you really need to pass manually classes, styles and refs? You really don’t have adequate built in way to write scoped styles? Your logic in component executes on EVERY re-render unless you specify all required deps manually in useMemo? You cannot conditionally call hooks? Your suspense is just terrible. What the hell is styled components and why it even exists. You cannot share data using context because it brings extra re-renders. SSR frameworks brings so much unnecessary complexity. What the hell is useCallback? You really cant pass a simple callback without breaking caching
@tarasturchenko4528
@tarasturchenko4528 Месяц назад
React was great at the start. It opened the era of spa frameworks but now it just retired
@EddieMarzo
@EddieMarzo Месяц назад
React becomes to Svelte. Svelte becomes to React.
@selambengp
@selambengp Месяц назад
Exactly!
@PhilipAlexanderHassialis
@PhilipAlexanderHassialis Месяц назад
With one HUGE caveat. Svelte doesn't have to work with v-dom. Svelte already transpiles everything to something that will only be rendered *once* . Yes, svelte has runes and effects and whatnot and makes the "feeling" of the code the developer rights a tad more "react-y" - but the end result is FAR different. This is why Svelte and Solid will always be in the top echelons of performance against react or vue or Angular (although Angular is pivoting on that and Vue is inching towards this direction). Axiomatically, v-dom will ALWAYS be worse in terms of performance, even by microseconds. There is no reconciliation, there is no diff-ing. I guess it depends on how deep you go on the end result, but the fact that React adds "auto-memo" doesn't mean that it will be ever close to Svelte. It will be close to what you and I would write to ensure peak performance *in the React bracket*. That's all.
@EgoOdiosis
@EgoOdiosis Месяц назад
​@@PhilipAlexanderHassialis vue will also become very similar to svelte 5 and solid once vapour is rolled out
@OnFireByte
@OnFireByte Месяц назад
It’s carcinization phase of web frameworks i guess
@kabukitheater9046
@kabukitheater9046 Месяц назад
i have used runes in a trial project. i promise you, it's waaaay better.
@azazinlove7514
@azazinlove7514 Месяц назад
React is a framework now
@paxdriver
@paxdriver Месяц назад
Why can't you build extensible rust? There's no reason in my mind that rust can't be developed with a system of future features easy to plug in. If a garbage collector can do it, then a system of add ons that easily plug into your existing project should be just as possible and reasonable in rust, doesn't it?
@jerondiovis6128
@jerondiovis6128 Месяц назад
The part about "we like our raw plain values in React" is exactly my feelings about Solid. Regardless of its good parts - I'm not wrting "just js" with it, I'm writing something very special Solid-compatible. "Don't use destructring because it will break reactivity" (which naturally leads to "don't use default values" and "don't spread objects" - use dedicated helpers for that), "don't assign functions directly, wrap them all in intermediate callbacks", "don't use async callbacks because our linter says so for some reason"... It quickly becomes so tedious to write, that I can only pick Solid because of necessity (like when I really need to save some bundle size), never because of personal choice. While with React basically the only rule is "don't call conditionally funcs starting with 'use' prefix" - and you're good to go.
@hereallyfast
@hereallyfast Месяц назад
Quiche eaters
@mateja176
@mateja176 Месяц назад
Prefer immutable array methods like toSorted, toReversed, toSpliced…
@jacoblockwood4034
@jacoblockwood4034 Месяц назад
Well these require polyfills since 10% of users don't support them yet
@ionutale1950
@ionutale1950 Месяц назад
Prima gen îs moving from rust to go, because his audience is majority go developers or golang fans. Man, Theo is just spreading misinformation
@hinstify
@hinstify Месяц назад
My employer does not use React in their projects. They only use Vue and Angular. When it comes to my personal project, I develop a 2D videogame, so not much use for React in there either... But I watch video about React anyway because I am curious, I guess. Also, Rust shills in comments incoming in 3..2..1... Dear Rust shills, please go back to programming microcontrollers
@dungtruong4105
@dungtruong4105 Месяц назад
React teams follow KISS (Keep it simple stupid) and HUGS (Help Understand, Guide, and Support) principles so well .
@naughtiousmaximus7853
@naughtiousmaximus7853 Месяц назад
What? 😂
@CoolestPossibleName
@CoolestPossibleName Месяц назад
Hi gabrielelpidio and RonanRU from twitch chat
@gusryan
@gusryan Месяц назад
14:57 would definitely rather have a when component than have to use ternaries
@fricze
@fricze Месяц назад
Use immutable data. Stop inventing weird shit. Thank me later.
@4v4
@4v4 Месяц назад
Like this if you like Dan
@osbyrne
@osbyrne Месяц назад
React is Quiche Eater slop - real programmers use SpringBoot
@swolebastard531
@swolebastard531 Месяц назад
Gotta love 'm spring beans
@Robert-G
@Robert-G Месяц назад
I’m quite certain that 80ies dude would call you a beans quiche eater 😂
@Caldaron
@Caldaron Месяц назад
7:40 toReversed() ;-)
@jacoblockwood4034
@jacoblockwood4034 Месяц назад
or just do the map before the reverse. Since toReversed is only supported with 90% so 1/10 users will error. Of course you can polyfill but I think .map(cb).reverse() is better
@johannesloher2817
@johannesloher2817 14 дней назад
You're all missing the point. Of course, there’s a good solution to this particular problem. But the actual issue is that it’s easy to get wrong by accident.
@matthewtaylor641
@matthewtaylor641 Месяц назад
Wild that React is taking this long to catch up to Vue 🙄
@mikopiko
@mikopiko Месяц назад
You'd never catch Theo mention Vue
@naughtiousmaximus7853
@naughtiousmaximus7853 Месяц назад
​@@mikopiko Vue is that busty hot latina that you know is better but you wont admit it.
@deadchannel8431
@deadchannel8431 Месяц назад
@@naughtiousmaximus7853vue is poo
@madmanali93
@madmanali93 Месяц назад
I hate the way vue does their templating. I'd rather stick with react
@doyouwantsli9680
@doyouwantsli9680 Месяц назад
Compiling scripts is a footgun. Use a compiled language, then.
@chuck_norris
@chuck_norris Месяц назад
step one: dont use react
@ari.joel.m
@ari.joel.m Месяц назад
step two: use jQuery
Далее
HTMX Sucks
25:16
Просмотров 110 тыс.
React Compiler: In-Depth Beyond React Conf 2024
15:16
`const` was a mistake
31:50
Просмотров 130 тыс.
React Native Bridgeless Mode for Dummies
6:43
Просмотров 4,6 тыс.
The Average React Developer
7:15
Просмотров 58 тыс.
How programmers flex on each other
6:20
Просмотров 2,2 млн
How React Query Won
34:52
Просмотров 69 тыс.
I Melted Wood With Friction
8:44
Просмотров 973 тыс.
Why I Use C | Prime Reacts
13:00
Просмотров 145 тыс.
Vapor: The Future Of Vue
21:27
Просмотров 113 тыс.
Prices & Poco M4 Pro 5G
1:00
Просмотров 267 тыс.
Prices & Poco M4 Pro 5G
1:00
Просмотров 267 тыс.