Author: Idle Fish Technology — Pang Zhi

An important part of the community: The circle was launched earlier this year

As a community-type product carrying “like-minded people based on interest gathering”, it has much higher requirements on business complexity, interaction complexity and performance and experience stability than conventional shopping guide products. Scenarios such as multi-role differentiation, nested scrolling, multi-form unlimited loading of Feeds, special character processing such as emoji, page opening, and video playback control are rarely encountered in shopping guide scenarios.

This article will focus on the front-end design and development of play circles encountered typical problems.

The key design

As shown in the diagram above, the overall business logic is relatively complex. And because there are applicationsMultiple role states, there are differences in user display interface and operation logic of different roles, and the cost of front-end development is high for students.

In order to reduce the cost of the front-end students to understand the global business in the development process, and reduce the problem of information transmission in communication. At the beginning of the design, we first carried out the split work of the smallest module. The corresponding work is allocated according to the module dimension, and the existing data sharing and data communication behaviors among modules are sorted and disassembled, so as to allocate the minimum closed loop of data state maintenance in an optimal way and reduce the coupling degree among components.

1. Split modules

The module defined here is not the modular component separation mentioned in daily front-end development, but a business unit that can be independent and closed loop. In this way, in the process of the project, the front-end students only need to focus on the interaction scene they are responsible for, except for the pre-agreement of data transfer between some components.   Take the circle module home page as an example. According to the design draft, we split it into three independent business modules: ** Circle information module, information flow module and floating layer component module. ** They are completely different both in function and display.

  • Circle information module: partial display module. Different types of module components need to be displayed according to the current identity of the user. In addition, the user can perform permission verification according to the current identity of the user, and provide friendly Tip prompt when the user does not meet the requirements.
  • ** Information flow module: ** partial interactive module. The module itself needs to maintain the user concern status table, blacklist filter table and video playlist to facilitate data sharing of sub-components in the module. In addition, the list has two layout modes of single row flow and waterfall flow, and the elements in the list have two types of cards: commodity and post content. Support comments, like to view the original picture, video playback, trigger floating layer and other interactive capabilities.
  • ** Floating layer module: ** universal module. Allows developers to register modules based on their business needs and to configure display positions, animation effects, and layer indexes

2. Split status values

Since there are many scenarios in the circle that need to share information, such as user-related data and basic information of the circle, it is not suitable to split the state based on the closed loop of business modules.

Therefore, after module splitting, we sorted out the state data of the circle homepage and split the state according to the principle of minimum rendering of components, as shown in the figure below:

Global state

As shown in the figure above, for the state variables with shared demands, we give priority to summarizing these state values together for unified processing.

However, because it is a C-end scenario, the interaction complexity is not high and the size of the resource bundle will have a certain impact on user experience. For the global state management scheme, we chose to use Rax native directlyuseReducer + useContextTo process and get the corresponding instancecontextThe simple demo code is as follows:

Business Component status

For non-shared data, it is required to put it into the container layer with the least impact of component rendering in the business module for maintenance. Take the single-row thread list as an example:

  • The initial card data is passed in as props, and the interactive data for a single post is maintained in the post element component layer.
  • In addition to the basic state information, the list container only controls the video playback and does not trigger container-level re-rendering.

The implementation of tuning

In the process of combined debugging of multiple business modules, we found that there were still many unsatisfactory problems in the interactive experience:

  • If there are too many display modules, the interaction of the whole page will appear obvious lag after data loading and switching under multiple tabs: for example, there will be obvious waiting delay when clicking to pop up the floating layer, and the corresponding subscript movement will not be synchronized when turning pages and switching between tabs.
  • Some components registered in the float container also trigger unnecessary rerendering when the shared variables change because they rely on shared variables: the effect is to flash a bit.
  • Unstable network conditions, page display is not friendly; The waiting time from the user clicking the route to jump to the display of the first screen page is too obvious, which is far from the page opening effect we require.

1. Reduce context. Provider rerendering

useContextWhile this can improve the ease of status value delivery, the problem is obvious: each status value update triggers the entireContext.ProviderAnd re-render the following subcomponents.

This is not consistent with our expected rendering process. After all, I may only be adjusting the values that a CircleHeader component depends on. There is no need for the following CircleSlider component and its list component to adjust the rendering, which is unacceptable.

By looking for solutions in the community, we found that there are a few tricks to solve this problem: Context.Provider components also maintain the same rules as Rax components: The props. Children attribute, as passed in, will not trigger the value diff if it is left unchanged, and thus will not cause any rerendering problems.

How do you make your Provider not re-render because of props. Children changes? Based on the community input, we see that each execution is createElement(XXX) after JSX escape. This can result in unnecessary rerendering because the resulting subcomponents are not consistent with each execution.

And to do that we willContext.ProviderSeparate into a higher-order component dedicated to passing state values, subcomponents toprops.childrenPass in the form of:In this way, we willCircleAppInto theStateless Component. Render only when the component is first initialized, and thenProviderThe page does not re-cause when the value changesGlobalContextProviderperformcreateElement(CircleApp``)To recreate the component instance and reduce unnecessary JS execution.

2. Adjust the component structure

As can be seen in the figure above, there are many pop-up scenarios of floating layer components in the circle. In the initial design process, floating layer components were considered because global shared variables also needed to be used. Therefore, at the beginning of the component structure design, the floating container components are placed in the global shared variablesGlobalContextProviderInside the component.

However, after the actual experience, we found that although it is more convenient for internal floating layer components to obtain shared variables, the feedback problem is also quite obvious: in the use of low-end models, if the page loads too much data, there will be an obvious sense of delay. And the floating layer component only needs to use the corresponding state value when it is actually displayed. When it is not displayed, the specific content of these data does not need to be related.

To do this, we adjusted the hierarchy of the floating container components and the home page resident components, as shown in the figure above: The resident component and layer containers were optimized from a nested structure to a parallel structure, with data communication between the two components triggered by method calls. The advantages of this adjustment are relatively obvious: first, floating components can be more general and reusable. All required parameters are passed in through the way of parameter passing, there is no need to strongly rely on the global shared state, for developers to maintain the cost is lower. Second, unnecessary re-rendering of child components is optimized by reducing the dependency on shared state values. It can also provide a relatively better interactive experience for low-end models.

3. First screen experience optimization + Dr Mechanism

In the experience optimization and upgrading campaign in the second half of last year, Xianyu’s front-end page experience has been greatly improved: the waiting time for the first screen of the page is greatly reduced, the content display is more friendly, and users can view the content data more quickly after each channel page is connected to the progressive first screen. However, in the process of circle development, we found that the progressive first screen scheme proposed before personalized recommended scenes could not be well supported. For this reason, we chose the degraded scheme, and adjusted the routing jump logic from the circle square page to the circle home page and related sub-pages.As shown in the figure above, data caching conventions between upstream and downstream pages are established to achieve DISASTER recovery and improve interaction experience. The corresponding business data is cached each time a page route jumps, and the next level of the page consumes the corresponding cached data. This can not only improve user experience in a poor network environment. At the same time when the interface error can play the lowest effective bottom, avoid the user body sense too bad.

Optimization before optimization after optimization

On this basis, in order to improve the rendering speed of the first screen of the page, we access the promotionData prefetch schemeandOffline package cacheSolution. Will the first screen page rendering process is the most time-consumingResource pack loading processandFirst screen interface request processParallelization is done to reduce the waiting time of the first screen display.Comparison of effects before and after optimization: Optimization before optimization after optimization

Follow-up prospects

The first version of circle play was released after various minor issues. In this process, some problems that have not been experienced before in e-commerce shopping guide scenarios are solved, such as role permission control and multi-state value management. These experiences can contribute to the growth of the complex C-terminal application system in the idle fish community.

However, there are still many problems for us to consider optimization:

  • At present, the average interaction time on the first screen of the circle homepage is about 1000ms, and there is basically no need for users to wait from clicking the entrance to browsing in the homepage. But we believe that by differentiating by device type, we can degrade some of the low – to mid-range capabilities at the beginning of the page to provide a faster interactive experience for this group of users.
  • In order to highlight the personality points of different circles in the community, I believe that the ability to customize the decoration and the ability to customize plug-ins will be essential later. How can we quickly access these business demands based on the existing architecture, which is what we need to think about in advance with our existing capabilities
  • How to make the components generated from the business modules as generic as possible and support multiple containers as business requirements change also needs to be addressed.