Home >Web Front-end >JS Tutorial >React Update Notes Companion

React Update Notes Companion

Linda Hamilton
Linda HamiltonOriginal
2025-01-12 16:39:44888browse

React Update Notes Companion

Update notes for new major versions of React are always incredibly information dense, and the framework itself is so broad that I always find myself taking notes and comparing vs reference documentation to try to not just figure out what changed and how to use it, but also how the various major concepts the update notes talk about actually worked under the hood. While React is extremely well documented, the update notes aren’t always “enough” to understand the concepts - for example, in the React 19 update notes, I found useOptimistic’s example confusing and actually a little inaccurate to how the hook actually works.

I’ve decided to write the notes I took while going over the React 19 changes into a companion for anyone who’s been dreading combing through the notes and figuring out what they all mean - so let’s get started.

Actions & Form Handling/useActionState

The first major improvement has been huge improvements to form handling. React has gradually been moving to remove boilerplate and better integrate with native HTML forms, and its new useActionState is part of this push. It’s intended to help improve error handling (as it’s now built-in), it automatically tracks loading states so that you don’t have to manually code in pending states constantly, and improves support for progressive enhancement.

Now, I found the code example provided for useActionState to be pretty confusing, and in fact this code example is the entire reason I started writing this article - there are, in fact, two parts to useActionState, which they combined in the example to save space, but ended up greatly reducing clarity. useActionState returns a tuple that tracks when the async action in the form submission is complete, while a modified version of the action you pass it is directly passed to the form. useActionState itself takes two inputs - an async formAction (which receives both the previous state and the form data as arguments when called) and the initial state - which can be null, zero, or a variable.

If your form hasn’t yet been submitted, the previous state is the initialState. If the form has been previously submitted, it’s whatever was submitted - in a server function, you can actually display the server response before hydration even happens. useActionState lastly can accept a string with a unique page url that the form is intended to modify. In other words, it can also accept an optional permalink parameter, which is particularly useful for progressive enhancement - it tells the browser where to navigate if a user submits the form before JavaScript has loaded.

Lastly, the tuple that useActionState returns is an array consisting of the current state (during your initial render it’s your initialState value), the react-modified formAction you can pass to a form as an action or a button as a prop, and an isPending flag/stateful variable. I’m looking forward to seeing what other new developments the React team will come up with, since this one seems particularly useful.

React-DOM updates

actions

This react-dom addition will be familiar to anyone who has been using NextJS and form actions, and it seems the Reac team has decided form actions are ready for prime-time. For anyone who hasn’t used them in NextJS or another framework on top of react, they are basically a way to enhance React’s performance by using native form submission. Instead of onClick, you can pass native form submissions via the action prop - any function passed to action or formAction will have its submission handled automatically. React will also automatically reset any uncontrolled form fields. You also have manual options for resetting it via API. The React team has also integrated error handling with error boundaries. I won’t talk too much about it since I’m assuming most people remember them from NextJS, but I can write a followup if anyone has questions.

useFormStatus hook

This is a great addition to help you see what’s going on in your form without prop drilling or using context - if you’re asking why not prop drill, it has to do with keeping code maintainable and easy to modify. As for context, overusing context is going to cause performance issues since every component subscribed to a particular context will rerender whenever something in the context changes. So it declutters code, reduces the chance of errors, and stops you from gumming up your app’s performance.

The hook returns an object with four properties: pending - a boolean that says if there’s a pending submission, data - a formData object with the data submitted by the parent form (this is null if there is no active submission or parent form), method (get or post), and action - which is the action being passed through the action prop.

useOptimistic hook

The new simpler way to manage optimistic updates. If you’re not familiar with optimistic updates, it means updating the client-side display before the server-side updates happen. If you’ve ever liked something, seen the animation play and had it register on your screen as liked, then received a toast error saying “like failed”, this is due to optimistic rendering.

The useOptimistic hook accepts a stateful variable you want optimistically rendered and an update function, which must be a pure function - in other words, a deterministic function with no side effects. Basically, the update function retrieves the source of the update to state - so typically something like formData.get(‘name’). useOptimistic then returns two values: the optimistic state and an addOptimistic function.

I found the documentation for this a little weak, particularly around the usage flow - basically, you call useOptimistic and pass it the initial state that you want to display optimistic updates for and an update function. You receive two functions - the newly optimistic-enhanced stateful value (optimisticState) and a function to optimistically change state. When you have a new value submitted by the user, you call the second function, referred to as addOptimistic in the docs, and pass it the user-submitted value. In your component, you then pass it the optimistic-enhanced stateful value whenever you want to render the stateful var optimistically.

Overall, I really like this more standardized way of performing optimistic updates - I’ve previously had issues with caching in NextJS and making optimistic updates, so a standardized way of creating optimistic updates is great, and I’m sure this will bubble up to NextJS, if it hasn’t already.

The use API

This is a super dense API, and it’s a brand new way to access resources while react is rendering a page - the exact phrasing used is “reading resources in render”. So what specifically is it for? This new API can be used to access component information inside of conditionals or loops. If you aren’t familiar with why this is useful, it has to do with how React’s rendering process works. React/react-fiber relies on rendering everything in the same order each time, which is why you can’t generally access most hooks during the rendering process. To put it more clearly, state is actually tracked based on the order hooks are called in, so if hooks are called in an unpredictable order, you end up with rendering bugs. A great example is accessing a theme context depending on whether or not the user is logged in.

So why is this an important development? It means that you can load information/data only when it’s actually necessary, e.g. only if a user is actually logged in will you load css for a special theme. The data has to be serializable, so that means you can send a promise from the server component to a client component while it is in fact already in flight - this means there are fewer waterfall requests and they are automatically put in parallel. It's worth noting that when working in Server Components, you should actually prefer using async/await over use for data fetching - this is because async/await will resume rendering from exactly where it left off, while use will trigger a full re-render of the component after the data resolves. Of course, I also want to note that this change actually also means you have a new potential source of waterfall requests if you configure use incorrectly.

One really important thing to note is that you cannot use the “use” API in a try/catch block - this is because “use” automatically uses react suspense boundaries when called with a promise. A try/catch block prevents you from ever reaching the react level since any error would actually stop execution on the JS level before you ever reach React, breaking the functionality. Like other hooks, they have to be in the top level of scope of a particular component or function (again, due to render order).

So, what is the actual purpose of “use” is to help you access context to render things conditionally and only fetch data when it’s actually necessary. It’s yet another step towards making react a bit less arcane, simplifying conditional data fetching, improving dev experience, and improving performance all in one fell swoop. It requires more experienced React devs to relearn how to do things like theming, but I think it makes the framework a lot more accessible to new users, which is always great.

New React Dom Static APIs

These two new static APIs, prerender and prerenderToNodeStream are both improvements to renderToString, which is used for Server Side Rendering (SSR). These new improvements are for doing Static Site Generation (SSG) using renderToString. Unlike traditional streaming SSR which can send content chunks as they become available, these new APIs specifically wait for ALL data to load before generating the final HTML. They're designed to work seamlessly with modern streaming environments like Node.js Streams and Web Streams, but they intentionally don't support streaming partial content - instead, they ensure you get complete, fully-loaded pages at build time. They differ from traditional streaming SSR methods, which send pre-rendered sites as data becomes available.

We already had SSG-capable frameworks built on top of React, like NextJS, but this is intended to be React’s native functionality for SSG. The frameworks that had SSG used renderToString, then built their own complex data fetching coordinations around it. This was extremely difficult for users to create themselves, and these frameworks used extremely complex pipelines to do so. What these new methods do is essentially allow for data to load during static HTML generation, If you aren’t familiar with SSG, it’s essentially rendering everything at build time, and is undoubtedly the fastest method of rendering pages, as it doesn’t have to render pages on user request, so it’s great to have this kind of functionality for people who don’t want to use something like Next, which either requires deployment on Vercel or an extremely complex deployment process.

Server Components

The concept of React Server Components won’t be new to anyone who’s used a recent version of NextJS, but for anyone who hasn’t, server components are a new paradigm around data fetching. Frankly, the concept of Server Components (and Server Actions) deserve an entire article themselves, but to sum up the concept briefly, server components are always rendered on the server before being sent to the client, even after javascript is loaded. That means subsequent renders are done server-side.

The main advantage of these components is security and data fetching: if you request data inside a server component, the request information never shows up client-side, only the response, making it much more secure. APIs, endpoints, etc. simply are not accessible client-side. It also reduces bundle size since the javascript for said actions is never sent to the client. It additionally allows you to execute memory or computationally intensive operations on the server to reduce the burden of rendering on less powerful machines. They also reduce client-side waterfalls since sequential data fetching can be performed on machines closer to your databases, but of course it also opens up the possibility of brand new server-side waterfalls since your devs lose access to easy request information from test browser developer tools and have to use something like an OpenTelemetry collector and viewer to examine them. Lastly, server components are also great for progressive enhancement.

Server components also come with a list of limitations: you can’t use local browser APIs (local storage, window, etc), react hooks will work differently, you can’t rely on or use state, and you can’t use event handlers, so user interactivity for the components is decidedly slim. Basically, think of this paradigm as data fetching in server components, interactivity on client components.

The most important caveat for anyone new to server components is that you cannot import them into a client component - if you do, this will error out (assuming you’ve added some data fetching) because it causes the compiler to treat said server component as a client component. If you want to pass a server component to a client component, you need to pass it via the {children} prop.

Server Actions

These are another complex topic with a lot of implications for how you build your products and features, and these have also been present in NextJS for a year or so. Server actions are declared by typing ‘use server’ at the top of a file, and pass a direct reference to said server function which can then be called from inside of a client component.

On some level, these are conceptually similar to Remote Procedure Calls (RPC) - they both let you call server-side functions from the client, both abstract the complexity of client-server interactions, and both handle serialization and deserialization, but there are a few key differences to be aware of. The main benefit of server actions is that they work with React’s progressive enhancement,, help enforce type-safety across client/server boundaries, have built-in performance optimizations (related to progressive enhancement), and have a more seamless integration with the React ecosystem in that they provide built-in pending states and are automatically integrated with native form submissions.

When you’re talking about modern RPC, something like gRPC that already has type safety and some performance optimizations, the main advantage of server actions generally boils down to said built-in form handling and progressive enhancement, but importantly it also works with react suspense and error boundaries. Most importantly, deployment is a lot simpler since you don’t necessarily need to set up separate server for gRPC, so these are absolutely more ideal for smaller projects, though when it comes to larger projects I can see gRPC being a lot more desirable since it gives you more flexibility in terms of backend language, etc.

Context as a Provider

This is essentially a simplification of the syntax, helping React in general have a much cleaner, declarative syntax. To be honest I don’t have much to say about this aside from “I like it”.

Ref as a Prop & Cleanup Functions for Refs

Previously, to clean up refs, you had to perform a null check inside of your component, and the ref would be cleaned up at a somewhat indeterminate time. React would call your ref callback with null when the component unmounted, requiring you to handle both the attachment and detachment cases explicitly. The advantage of the new ref syntax is deterministic cleanup - which means it’s now a lot easier to work with external resources and third party libraries because you will know exactly when ref cleanup happens (on unmount). With the new approach, you can return a cleanup function directly. The TypeScript integration requires explicit return statements to avoid ambiguity about cleanup functions.

I really like the way this was implemented since it’s the same pattern from useEffect - maintaining consistency across the framework is great. I think this new ref cleanup is specifically going to be really useful for WebGL contexts and other heavy resources, but also for handling DOM event listeners added using native JS methods. This is because previously, react would remove the ref to the dom element on cleanup…But then if you’ve done that, it becomes much more complex to remove event listeners since you’ve lost the reference to the component they’re attached to. As a result, you had to store your refs outside of the element, adding a layer of complexity. Now you can just remove event listeners inside your component’s return function because you retain access to the ref inside said return function. This also means we no longer need to worry about the null case in most situations, as React won't call the ref with null anymore when using cleanup functions. The cleanup function itself replaces that functionality, making our code cleaner and more predictable.

useDeferredValue

The purpose of the useDeferredValue hook is to manage computationally expensive operations while maintaining a responsive user interface. It accomplishes this by allowing components to show a previous "stale" value while calculating or fetching new data in the background. A common use case is search functionality that displays results as users type - without deferring, each keystroke could trigger an expensive search operation that makes the input feel sluggish. Using useDeferredValue, the interface can remain responsive by showing previous search results while computing new ones.

This new addition is an important improvement to this hook's initial loading behavior. Previously, the first render would immediately use whatever value was passed to useDeferredValue, potentially triggering an expensive computation right at the start. The new version allows you to provide a lightweight initial value (such as an empty string) that displays immediately, while processing the more expensive value in the background. This means you can show users immediate feedback with a safe default value, then update it with real data once the expensive computation completes. Essentially, this makes useDeferredValue even better for performance improvement.

Document Metadata Additions

These new changes are for adding various metadata tags inside of actual components. There are three options they go over: , , and <meta>. It’s important to note that <title> has no deduplication - you’re only intended to use it once per repo. The other two, <link> and <meta>, have some pretty complex interactions regarding deduplication that, after learning, I think aren’t going to be particularly relevant for 90% of users. </p> <p>The main benefit from these changes is that they allow components to truly be self-contained: they can now manage their own metadata along with their styles and scripts. You don’t need to figure out how to lift metadata to the top level or make use of a library to do it anymore, which makes SEO far easier to do. Different pages in an SPA can have different metadata more easily without risking metadata becoming out of sync with the content displayed on the page, which was previously a risk when having different metadata for different pages.</p> <p><strong>Stylesheet Support</strong></p> <p>People may have been using tailwind so long that they’ve forgotten, but running non-encapsulated CSS can create issues due to how stylesheets are loaded - namely, load order precedence rules. First, you can end up with flashes of unstyled content - any time the HTML loads and renders before the CSS is finished downloading, it displays as a completely white page, typically in a single column with massive font sizes and native image sizes, which often makes it unreadable.</p> <p>Additionally, CSS load order rules can create other problems: for example, if you have rules with the same specificity but expect them to load in a certain order. This is relevant, for example, when you have different options for themes (e.g. dark mode). If the dark mode CSS is intended to load last, but your CSS file for dark mode loads first, you can end up with dark mode being light, or some parts of the app where the rules are adhered to and other parts where they aren’t adhered to. </p> <p>There were a lot of solutions for avoiding this, like CSS in JS, loading all CSS in the <head> tag, build time bundling CSS together, etc. However, these new CSS changes are intended to help manage these issues by declaratively setting precedence - it also ensures any stylesheets placed in a component are loaded before the component itself renders. It’s also got built in deduping, so you don’t end up loading the same stylesheet multiple times when you reuse components with stylesheet links included. </p> <p>The way you access this new functionality (waiting for the css to load before rendering a component, hoisting CSS automatically to the head, etc.) is pretty simple too - you just need to include a precedence in a particular <link> component. Overall, I’m a typescript enjoyer, so it doesn’t exactly address any particular issues for me, but I’m sure this will be extremely useful large legacy projects. </p> <p><strong>Async Script Support</strong></p> <p>This addresses an edge case, as opposed to creating a new core functionality for people to worry about - manually adding/directly managing scripts with a <script> tag is pretty rare in modern React in my experience. Most devs are using bundlers like webpack or vite, package managers, import statements, and if scripts need to be dynamically loaded they use something like useEffect. However, this is relevant for SSR and better UX to avoid the aforementioned issues with load order of the contents in the <head>. </p> <p>Since scripts can be loaded asynchronously, it means there’s a significantly lower chance of react apps loading without proper styles. The change is also relevant for devs managing legacy systems that require direct script tags or devs responsible for managing third-party scripts that can’t be bundled (e.g. analytics, widgets, etc.), or preventing a particularly heavy script (e.g. a video player) loading before it’s necessary to improve performance, but since I don’t have experience with those, I can’t really comment much more than that. </p> <p><strong>Support for Preloading Resources</strong></p> <p>The new APIs for managing resource preloading are quite interesting, particularly for larger enterprises that have to ensure seamless loading experiences for global audiences with widely varying network conditions, for particularly content-heavy apps that rely on heavy third party resources from different sources, and for any app where perceived performance is important to user retention (which, to be honest, is nearly everything) </p> <p>However, most frameworks that sit on top of react (e.g. Next, Remix, etc.) tended to already manage this - I’m not quite sure how these new APIs will interact with said frameworks, but it seems like it’ll be a new source of conflicts and something important to keep in mind when using these frameworks and attempting to optimize performance using these new APIs. </p> <p>While preload is definitely the API with the widest use case (loading stylesheets etc.), thanks to the above issue the one I think has the most relevance is preinit - it’s a hard load that starts immediately and is intended for eagerly loading scripts. The most obvious use I can think of is something like immediately loading stripe on shopping cart review - this should speed up the checkout process significantly, which is a step of e-commerce where you absolutely don’t want to lose customers due to performance issues. </p> <p><strong>Third Party Script Compatibility</strong></p> <p>This is a pretty welcome change given how increasingly common browser addons are - some examples I can think of that modify DOM structure that probably benefit from this change are ad blockers, price comparison tools, grammar/AI assistant addons, and translation extensions. Not much else to say about this without actually reading how hydration works now, though it seems the main change is that the compiler skips over unexpected tags. </p> <p><strong>Better Error Reporting</strong></p> <p>I found this section to be pretty self-explanatory. Error handling changes are always welcome - the error spam that previously existed always made it a bit harder to track down specific errors. This is particularly relevant if you use some less well maintained third party solutions that tend to fire off a ton of errors.<br> Support for Custom Elements</p> <p>This section was particularly interesting to me since I hadn’t heard of Custom Elements before. The rundown is that Custom Elements are a new web standard to let devs create their own HTML elements. Thanks to following said web standards, they’re intended to function on any page and be framework agnostic - for example you could write a component you commonly use in all your personal projects, which you tend to do in svelte, then use it for smaller contract work you do for startups or short term contracts in vue, etc. </p> <p>React used to treat unrecognized props as attributes instead of actual properties - the new update has added a system that allows props to be properly used to create custom elements. It seems with this change, there is now full support for using Custom Elements in react. On a side note, in addition to the props issue, there used to also be incompatibilities (now resolved) with react’s synthetic events system - Custom Elements couldn’t cleanly integrate with the system, so there were some cases where you actually had to manually add event listeners with ref, among other workarounds. </p> <p>The above is the detailed content of React Update Notes Companion. For more information, please follow other related articles on the PHP Chinese website!</p></div><div class="nphpQianMsg"><a href="javascript:void(0);">JavaScript</a> <a href="javascript:void(0);">typescript</a> <a href="javascript:void(0);">css</a> <a href="javascript:void(0);">less</a> <a href="javascript:void(0);">html</a> <a href="javascript:void(0);">edge</a> <a href="javascript:void(0);">webpack</a> <a href="javascript:void(0);">Static</a> <a href="javascript:void(0);">String</a> <a href="javascript:void(0);">Boolean</a> <a href="javascript:void(0);">Array</a> <a href="javascript:void(0);">Object</a> <a href="javascript:void(0);">NULL</a> <a href="javascript:void(0);">Resource</a> <a href="javascript:void(0);">if</a> <a href="javascript:void(0);">for</a> <a href="javascript:void(0);">while</a> <a href="javascript:void(0);">include</a> <a href="javascript:void(0);">require</a> <a href="javascript:void(0);">try</a> <a href="javascript:void(0);">catch</a> <a href="javascript:void(0);">Error</a> <a href="javascript:void(0);">register</a> <a href="javascript:void(0);">using</a> <a href="javascript:void(0);">Interface</a> <a href="javascript:void(0);">Conditional</a> <a href="javascript:void(0);">Event</a> <a href="javascript:void(0);">var</a> <a href="javascript:void(0);">JS</a> <a href="javascript:void(0);">function</a> <a href="javascript:void(0);">default</a> <a href="javascript:void(0);">dom</a> <a href="javascript:void(0);">this</a> <a href="javascript:void(0);">promise</a> <a href="javascript:void(0);">display</a> <a href="javascript:void(0);">background</a> <a href="javascript:void(0);">animation</a> <a href="javascript:void(0);">column</a> <a href="javascript:void(0);">input</a> <a href="javascript:void(0);">kind</a> <a href="javascript:void(0);">rpc</a> <a href="javascript:void(0);">ux</a> <a href="javascript:void(0);">issue</a> <a href="javascript:void(0);">webgl</a> <a href="javascript:void(0);">everything</a> <a href="javascript:void(0);">Access</a> <a href="javascript:void(0);">SEO</a> <a href="javascript:void(0);">Other</a><div class="clear"></div></div><div class="nphpQianSheng"><span>Statement:</span><div>The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn</div></div></div><div class="nphpSytBox"><span>Previous article:<a class="dBlack" title="Building an AI-Powered Background Remover with React and Transformers.js" href="https://m.php.cn/faq/1796752021.html">Building an AI-Powered Background Remover with React and Transformers.js</a></span><span>Next article:<a class="dBlack" title="Building an AI-Powered Background Remover with React and Transformers.js" href="https://m.php.cn/faq/1796752027.html">Building an AI-Powered Background Remover with React and Transformers.js</a></span></div><div class="nphpSytBox2"><div class="nphpZbktTitle"><h2>Related articles</h2><em><a href="https://m.php.cn/article.html" class="bBlack"><i>See more</i><b></b></a></em><div class="clear"></div></div><ins class="adsbygoogle" style="display:block" data-ad-format="fluid" data-ad-layout-key="-6t+ed+2i-1n-4w" data-ad-client="ca-pub-5902227090019525" data-ad-slot="8966999616"></ins><script> (adsbygoogle = window.adsbygoogle || []).push({}); </script><ul class="nphpXgwzList"><li><b></b><a href="https://m.php.cn/faq/1609.html" title="An in-depth analysis of the Bootstrap list group component" class="aBlack">An in-depth analysis of the Bootstrap list group component</a><div class="clear"></div></li><li><b></b><a href="https://m.php.cn/faq/1640.html" title="Detailed explanation of JavaScript function currying" class="aBlack">Detailed explanation of JavaScript function currying</a><div class="clear"></div></li><li><b></b><a href="https://m.php.cn/faq/1949.html" title="Complete example of JS password generation and strength detection (with demo source code download)" class="aBlack">Complete example of JS password generation and strength detection (with demo source code download)</a><div class="clear"></div></li><li><b></b><a href="https://m.php.cn/faq/2248.html" title="Angularjs integrates WeChat UI (weui)" class="aBlack">Angularjs integrates WeChat UI (weui)</a><div class="clear"></div></li><li><b></b><a href="https://m.php.cn/faq/2351.html" title="How to quickly switch between Traditional Chinese and Simplified Chinese with JavaScript and the trick for websites to support switching between Simplified and Traditional Chinese_javascript skills" class="aBlack">How to quickly switch between Traditional Chinese and Simplified Chinese with JavaScript and the trick for websites to support switching between Simplified and Traditional Chinese_javascript skills</a><div class="clear"></div></li></ul></div></div><ins class="adsbygoogle" style="display:block" data-ad-format="autorelaxed" data-ad-client="ca-pub-5902227090019525" data-ad-slot="5027754603"></ins><script> (adsbygoogle = window.adsbygoogle || []).push({}); </script><footer><div class="footer"><div class="footertop"><img src="/static/imghwm/logo.png" alt=""><p>Public welfare online PHP training,Help PHP learners grow quickly!</p></div><div class="footermid"><a href="https://m.php.cn/about/us.html">About us</a><a href="https://m.php.cn/about/disclaimer.html">Disclaimer</a><a href="https://m.php.cn/update/article_0_1.html">Sitemap</a></div><div class="footerbottom"><p> © php.cn All rights reserved </p></div></div></footer><script>isLogin = 0;</script><script type="text/javascript" src="/static/layui/layui.js"></script><script type="text/javascript" src="/static/js/global.js?4.9.47"></script></div><script src="https://vdse.bdstatic.com//search-video.v1.min.js"></script><link rel='stylesheet' id='_main-css' href='/static/css/viewer.min.css' type='text/css' media='all'/><script type='text/javascript' src='/static/js/viewer.min.js?1'></script><script type='text/javascript' src='/static/js/jquery-viewer.min.js'></script><script>jQuery.fn.wait = function (func, times, interval) { var _times = times || -1, //100次 _interval = interval || 20, //20毫秒每次 _self = this, _selector = this.selector, //选择器 _iIntervalID; //定时器id if( this.length ){ //如果已经获取到了,就直接执行函数 func && func.call(this); } else { _iIntervalID = setInterval(function() { if(!_times) { //是0就退出 clearInterval(_iIntervalID); } _times <= 0 || _times--; //如果是正数就 -- _self = $(_selector); //再次选择 if( _self.length ) { //判断是否取到 func && func.call(_self); clearInterval(_iIntervalID); } }, _interval); } return this; } $("table.syntaxhighlighter").wait(function() { $('table.syntaxhighlighter').append("<p class='cnblogs_code_footer'><span class='cnblogs_code_footer_icon'></span></p>"); }); $(document).on("click", ".cnblogs_code_footer",function(){ $(this).parents('table.syntaxhighlighter').css('display','inline-table');$(this).hide(); }); $('.nphpQianCont').viewer({navbar:true,title:false,toolbar:false,movable:false,viewed:function(){$('img').click(function(){$('.viewer-close').trigger('click');});}}); </script></body><!-- Matomo --><script> var _paq = window._paq = window._paq || []; /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() { var u="https://tongji.php.cn/"; _paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setSiteId', '9']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })(); </script><!-- End Matomo Code --></html>