By Liu Xianning

In this paper, starting from InfoQ:http://www.infoq.com/cn/articles/front-end-component-develop-and-application-in-react-native

With SPA, the technology architecture of front and back end separation is becoming more and more popular in the industry. The front end (note: in this paper, the front end refers to all user accessible interfaces, including desktop and mobile terminal) needs to manage the content and assume more and more responsibilities. Coupled with the popularity of Mobile Internet and the Mobile First trend, major companies began to invest more resources in the front end.

All this, for the front-end development plan on the thinking of a lot more, represented by the React framework of modular development plan, is now the industry is recognized this article will explore the componentization with everybody together what can bring us development plan, and how to React Native project using modular development plan.

First, why to use the componentized development plan?

Before I talk about how to do this, I need to take a look at why the front end uses component development solutions. As a programmer and consultant, I know that it’s always a bad idea to talk about solutions without talking about problems. What are the problems with front-end development as more business functions are pushed to the front end and development teams expand as the business grows in size?

1. Problems of front-end development

  1. Resource redundancy: As pages become more numerous, page interactions become more complex. In this case, some team members will write their own CSS and JS according to the function, which will result in a large number of new CSS or JS files, which may have a lot of repetitive logic. Some team members reuse other people’s logic, but due to granularity differences in logic splitting, they may need to load an entire module in order to rely on a function in a JS, or rely on an entire CSS file in order to use a partial style in a CSS, resulting in a great deal of resource redundancy.
  2. Dependencies are not intuitive: When modifying a JS function or a CSS property, many times you can only rely on human global search to determine the scope of influence, which is not only slow, but also prone to error.
  3. Poor flexibility and maintainability of the project: because there are too many cross-dependencies in the project, when the technical solution changes, the old code cannot be replaced gradually and rhythmically, but all the old code can be replaced at one time, which greatly increases the cost and risk of the technical solution upgrade.
  4. It is difficult for newcomers to get started: after they enter the project, they need to understand the background of the whole project and the technology stack before they dare to start working. This may not be a problem in small projects, but in large projects, especially those with high turnover, it can have a significant impact on the project schedule.
  5. Team coordination degree is not high, the user process on the dependencies between the page (for example, a page is strong work results depend on the previous page), as well as the mutual dependence on some of the technical scheme (for example, a file can only be amended by a team) will lead to can’t play all the effectiveness of a team, some members will be waiting for the empty window period, waste team efficiency.
  6. Test difficulty: Unclear logical breakdown throughout the project and excessive and messy interdependencies significantly increase the difficulty of automated testing.
  7. Slow communication and feedback: Business requirements and UX designs wait until developers have written the code and the project is compiled and deployed to see the actual results. This feedback cycle is too long, and the entire process is repeated for any minor changes in the future.

2. Benefits of componentized development

The core of componentized development is “business to business, component to component”. A component is an independent module that has the following characteristics:

(Photo: http://serenity.bh/wp-content/)

  • Responsibilities are single and clear: developers can easily understand the capabilities provided by this component.
  • High resource cohesion: Component resources have high internal cohesion, and component resources are completely controlled by their own loading.
  • Scope-independent: The internal structure is sealed and does not affect global or other components.
  • Interface normalization: There is a uniform specification for component interfaces.
  • Can be combined with each other: assembly and integration into complex components, high-order components, etc.
  • Independent and clear lifecycle management: components must have a clear and controlled path for loading, rendering, and updating.

The business is to complete the User Journey by assembling a bunch of components. In the next section, we will describe in detail how a team with a componentized development approach works.

In the project, the relationship between components and business can be clearly distinguished, and the construction architecture of the system can be componentized.

  1. Reduce coupling throughout the system: We can upgrade the business function by replacing the current component with a different component, such as a search box with a calendar component, while keeping the interface unchanged.
  2. Improved maintainability: Because each component has a single responsibility, it is easier to reuse it in the system. Therefore, a change in a responsibility only needs to be changed to achieve an overall upgrade of the system. Stand-alone, small component code is easier to understand and maintain.
  3. Easy to get started: New members only need to understand the interfaces and responsibilities to develop component code, and further understand and learn about the project as they develop. In addition, because the scope of the code is limited to components, it is very helpful to control the risk of the project, and there is no avalanche of changes that can affect the entire team’s work.
  4. Improve team collaborative development efficiency: through the granularity control of component splitting, team members can be reasonably assigned tasks, so that everyone in the team can give full play to their strengths, maintain corresponding components, and maximize team development efficiency.
  5. Facilitate automated testing: Since components are completely autonomous kingdoms except for their interfaces, they can even be conceptually treated as a function, with inputs corresponding to outputs, which makes automated testing easy.
  6. Easier self-documentation: On top of components, a Living Style Guide can be used to create a ‘Living’ document for all the UI components of a project. This document can also serve as a bridge between business, development, and UX. This is another interpretation of “code is documentation”, which neatly solves the problem that programmers don’t like to document.
  7. Easy debugging: Because the whole system is composed of components, when problems occur, you can use the elimination method to remove components directly, or according to the components reported by the fault quickly locate the problem. In addition to being a communication tool, the Living Style Guide can also be used as a debugging tool to help developers debug UI components.

Ii. How does the team operate under the componentized development scheme?

Now that we’ve talked about the benefits that componentized development can bring to a project, let’s talk about how a team that adopts a componentized development solution should operate.

At ThoughtWorks, we divide the life cycle of a project into the following phases:

The componentized development approach focuses on improving team efficiency during the iterative development phase. It mainly improves the development efficiency from the following aspects:

1. Reduce workload through component reuse of architecture layer

In the back-end development of large applications, the idea and method of abstracting applications into relatively independent modules at the architectural level for division of labor, reuse, and maintainability has been very mature and well accepted.

But in front-end developer, or a more traditional modular thought, developers or only will reuse should be considered in a certain part to make components, plus when developers focus on different interface development, for the lack of focus on the interface which can be reused, resulting in multiple interface to repeat the same UI function development, This not only increases the workload of the entire project, but also increases the cost of subsequent modification and maintenance.

In a component-development scenario, the team needs to modularize the application’S UI at the architectural level at the start of delivery. Together, the team abstracts each UI page in the prototype produced during the requirements analysis phase into a tree of components, and the UI page is itself a component. The diagram below:

With the above abstractions, we can see that a large number of components can be reused across multiple UI interfaces, and considering that building UI interfaces accounts for more than 80% of the work in a front-end project, such abstractions significantly reduce the amount of work on the project, as well as help with subsequent modifications and maintenance.

Under such an architectural pattern, the way the team operates needs to change accordingly:

  1. Engineering support, emphasis on componentized thinking for developers from the division of the directory structure, distinguishing the location, responsibilities, and dependencies of base components, business components, and page components.
  2. Prioritizing work. In agile teams, we emphasize delivering business value. Business is composed of page components in series. Under the componentized architecture mode, it is necessary to complete component development first and then series business. Therefore, in iteration planning, a clear prioritization of the team’s task of developing components and the task of connecting the business is needed to keep the team on track to deliver business value.

2. Ensure the unity of project design with the standardization of components

In front-end development, because of the flexibility of CSS, for the same UI requirements (such as: layout on the right border of 5 pixels), there may be ten CSS writing methods, the developer’s background, experience is different, it is likely to choose different implementation methods; There are even some immature projects. The demander directly provides a PDF file of user flow chart interface instead of PSD. All design elements need to be captured by the developer from the picture, which will make the style of the project varied. Because there are many ways to write the same UI design in the project, it will lead to many problems. First, there may be inconsistency in the design. Second, when the UI design is modified, there will be the cost of multiple modification schemes, or even the problem of bugs caused by missing a certain style.

Under the componentized development scheme, the unity of project design is pulled up to the component layer, which is guaranteed by the unity of components. In fact, originally all business UI design is component as a unit, designers do not say I want “yellow”, they say I want “yellow button…” . It is developers who delegate UI design to CSS styles during implementation, so components are more integrated and understandable than individual, set of CSS properties. This, combined with the highly cohesive nature of the component’s resources, makes it easier to tweak styles on the component and its scope of influence more manageable.

In a componentized development scenario, in order to ensure the consistency of UI design, the team operation needs to:

  1. Define base design elements, including color points, fonts, size, etc., all base design elements are determined by UX.
  2. All concrete UI component designs must be combined through these base design elements, and if the current base design elements do not meet the requirements, there will be discussions with UX to add base design elements.
  3. Acceptance of UI components requires UX participation.

3. Improve team coordination efficiency with component independence and autonomy

In front-end development, there is a typical scene is a functional interface, there are many levels from the start interface, according to the traditional development mode, need to be page by page development, the current page development is not completed, can not start the next page development, resulting in the team work concurrency is not enough. In addition, in the team, developers have different abilities, and page dependence reduces the flexibility of the whole project in task arrangement, making it impossible for us to arrange work reasonably according to the experience and strengths of team members. The influence of these two factors on team synergy will eventually drag down the overall efficiency of the team.

Under the componentized development scheme, the separation and coordination between business tasks and component tasks are emphasized. Component tasks are highly independent and autonomous, meaning that when interfaces are clearly defined, they can be developed without context. This type of task has no external dependencies and, combined with the component’s single responsibility, its functionality is easily understood by the developer.

So component tasks can be very flexible in how they are scheduled. A business task, on the other hand, only needs to see if the component it depends on has been completed, and as soon as it is, it enters the Ready For Dev state, waiting For the next developer to pick it up with the highest priority.

Under the componentized development scheme, in order to improve team synergy efficiency, the team operation needs to:

  1. Separate business tasks from component tasks, component to component, and business to business.
  2. Manage the dependency of business tasks on component tasks using team management tools such as Jira, Mingle, etc., making it easy for the team to understand the tasks needed to achieve each business value.
  3. Tech Lead needs to deepen the understanding of each member of the team and clearly know their strengths as a reference when arranging tasks.
  4. The business priority principle is that the business task takes the highest priority as soon as all component tasks dependent on the business task are completed, and the team takes delivering business value as the highest priority.
  5. Component tasks are completed before business tasks are included in the business stream, and teams need tools like a Living Style Guide to help them accept component tasks.

4. Reduce team communication costs with the component Living Style Guide platform

In front end development, there are often communication scenarios like this:

  • Developers and UX validate page designs by making repeated small changes to the UI for minor differences.
  • As developers and business people validate interface processes, the UI is modified repeatedly for specific needs.
  • A developer wants to reuse another component, and the developer looking for that component understands its design and responsibilities
  • Developers and QA work together to verify the impact of a common component change on multiple interfaces

When such communication occurs in the scenario mentioned in the previous section, where the component appears in an interface that is several levels away from the launch interface, traditional UX and development require multiple clicks, and sometimes even data input, to reach the desired functional interface. The absence or inability to build an intuitive platform to meet these requirements leads to a long, repetitive path for each communication change. The communication cost of the team soared, greatly reducing the development efficiency.

Under component-based development, building a Living Style Guide platform is easy because of component independence, and there are already many tools available in the community to support building a Living Style Guide platform (such as GetStoryBook).

Developers simply add components as demos to the Living Style Guide platform, and all communication about UI components is platform-centric, since changes to the components are immediately visible on the platform. Coupled with the fact that the platform organizes components in such a way that everyone has direct access to whatever components they need, the “WYSIWYG” communication saves a lot of costs by allowing developers to quickly modify and validate any requirements that UX and business people have.

In addition, the platform has its own component document function, and team members can see UI and interface of all components from the platform, which reduces the lack of component context knowledge caused by personnel changes, and also reduces the communication requirements between developers for components.

To reap these benefits, the team’s operations require:

  1. The Living Style Guide platform was built at the beginning of the project.
  2. Developers must add demos to the platform after completing the component, or even several more depending on the scenario the component needs to adapt to. This allows you to see at a glance what the component looks like in different scenarios.
  3. UX, business people can accept components through the platform, and even modify component Props on the platform to test the response of components in extreme scenarios.

5. Assistance in demand analysis stage and product evolution stage

Although demand analysis and product evolution phase is not modular development focus, but the effect of modular development related to these two stages, componentized solution need to demand analysis stage to give a clear Domain data structure, basic design elements and interface prototype, they are the basis for development of componentization. For product evolution, componentized development provides two important features that greatly reduce the risk of product evolution:

  • The low-coupling architecture allows developers to know the impact of their changes and reduces the risk of evolution. Development teams simply need to complete new components to meet new requirements, or replace existing components to complete product evolution.
  • The self-documentation capability of the Living Style Guide makes it easy to obtain information about existing component code, reducing the risk of loss of context in product evolution due to staff turnover.

Iii. Implementation of componentized development scheme in React Native Project

The reasons and how to make componentized development solutions have been discussed in detail. Next, take a React Native project as an example to see the implementation of componentized solutions from the code level.

1. Define basic design elements

As mentioned earlier, the requirements analysis phase produces the basic design elements that need to be added to the code before the front-end developer can start writing it. In React Native, all CSS properties are encapsulated in JAVASCRIPT code, so you don’t need LESS, SCSS or any other dynamic style language in React Native, and you can use all the features of THE JAVASCRIPT language to help you combine styles. So we can create a single theme.js file to store all the base design elements, or split it into multiple files if there are many base design elements.

import { StyleSheet } from 'react-native'; module.exports = StyleSheet.create({ colors: {... }, fonts: {... }, layouts: {... }, borders: {... }, container: {... }});Copy the code

Then, after writing the styles of the specific UI component, just import the file and reuse the style properties according to THE RULES of JS.

2. Split the Component tree into Component, Page, Scene

Before implementing the business flow, the prototype UI of the project needs to be decomposed and classified. In the React Native project, I divided the UI components into four types:

  • Shared Component: Base Component, which is used by most other components such as buttons, labels, etc
  • Feature Component: Business components that correspond to sub-components of a business process but do not correspond to routes. They form Pag components through various combinations.
  • Page: Indicates the Container component corresponding to a route. It combines sub-components. It is recommended that the names of all Page components end in Page for easy identification.
  • Scene: a connector between the application state and the UI. It is not a UI component in the strictest sense. Its main function is to bind the application state to the Page component.

The Component and Page components are Pure components that only receive props and display the UI in response to events. The Component Props is passed to it by the Page Component, and the Page Component Props is bound to it by the Scene Component. Let’s take a look at the responsibilities of each of these components using the following page as an example:

(1) searchResultRowItem. Js

export default function (rowData) { const {title, price_formatted, img_url, rowID, onPress} = rowData; const price = price_formatted.split(' ')[0]; return ( <TouchableHighlight onPress={() => onPress(rowID)} testID={'property-' + rowID} underlayColor='#dddddd'> <View>  <View style={styles.rowContainer}> <Image style={styles.thumb} source={{ uri: img_url }}/> <View style={styles.textContainer}> <Text style={styles.price}>{price}</Text> <Text style={styles.title} numberOfLines={1}>{title}</Text> </View> </View> <View style={styles.separator }/> </View> </TouchableHighlight> ); }Copy the code

(2)SearchResultsPage.js

import SearchResultRowItem from '.. /components/searchResultRowItem'; export default class SearchResultsPage extends Component { constructor(props) { super(props); const dataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1.guid ! == r2.guid}); this.state = { dataSource: dataSource.cloneWithRows(this.props.properties), onRowPress: this.props.rowPressed, }; } renderRow(rowProps, sectionID, rowID) { return <SearchResultRowItem {... rowProps} rowID={rowID} onPress={this.state.onRowPress} />; } render() { return ( <ListView style={atomicStyles.container} dataSource={this.state.dataSource} renderRow={this.renderRow.bind(this)} /> ); }}Copy the code

(3)SearchResultsScene.js

import SearchResults from '../components/searchResultsPage';
function mapStateToProps(state) {
  const {propertyReducer} = state;
  const {searchReducer:{properties}} = propertyReducer;
  return {
    properties,
  };
}

function mapDispatchToProps(dispatch) {
  return {
    rowPressed: (propertyIndex) => {
      dispatch(PropertyActions.selectProperty(propertyIndex));
      RouterActions.PropertyDetails();
    }
  };
}

module.exports = connect(
  mapStateToProps,
  mapDispatchToProps,)(SearchResults);
Copy the code

3.Living Style Guide

The best Living Style Guide for React Native is GetStoryBook. How to use GetStoryBook to build the React Native Living Style Guide platform can be found in the official documentation or on my blog.

After setting up the Living Style Guide platform, you can see the following interface:

The next step is to keep adding demos of UI components to the platform. Adding a Demo to a storybook is easy. Here is a Demo for SearchPage:

import React from 'react'; import {storiesOf, action} from '@kadira/react-native-storybook'; import SearchPage from '.. /.. /.. /.. /src/property/components/searchPage'; storiesOf('Property', module) .add('SearchPage', () => ( <SearchPage request={{place_name:"London"}} isLoading={false} search={action('Search called')}/> ));Copy the code

As you can see from the code above, there are only three simple steps to complete a UI component Demo:

  1. Import UI components for Demo.
  2. StoriesOf defines a directory of components.
  3. Add Adds Demo.

While building the storybook for your project, here are a few Tips to help us develop the Demo more effectively:

  1. Align the directory structure with the source structure as much as possible.
  2. Each UI component corresponds to a Demo file. To maintain the independence and flexibility of the Demo code, you can add multiple Demos to a component so that you can see the Demo status in multiple scenarios at a glance.
  3. The Demo name is the UI component name plus the Demo suffix.
  4. In a scenario where component parameters are complex, a separate directory for fakeData can be provided to store the reused UI component Props data.

4. A complete business development process

After completing the above three steps, a complete React Native business development process can be divided into the following steps:

  1. Use basic design elements to build base components, approved by the Living Style Guide.
  2. Compose business components using base components, accepted in the Living Style Guide.
  3. Using business components to compose Page components, accepted by the Living Style Guide.
  4. Use Scene to associate the Page component’s state with the application’s.
  5. Use the Router to concatenate multiple scenes to complete the business process.

Four,

As the front end separation architecture becomes the mainstream, more and more business logic is pushed to the front end, and users have higher requirements for experience, the complexity of the front end is increasing step by step. Managing front-end complexity becomes increasingly important. Through various frameworks and tools of the front end, we have made a lot of progress in front end engineering practice. Component-based development is one of the better directions for me, because it not only focuses on current project delivery, but also guides the team, helps evolve later, and even provides a clever solution to the most annoying aspect of writing documents for programmers. I hope the students who are interested in this method can study together and improve it.


For more insights, please follow our wechat official account: Sitvolk