1. Background
Hippy provides a Navigator component for page navigation and jumping.
However, the Navigator component has major limitations. It is implemented by starting a new Instance of Hippy. Under 2.0, instances may not be able to communicate with each other.
The functions of @hippy/ React and @hippy/ react-Web Navigator components are relatively lacking, and neither of them has a good function to realize page hopping. There are also differences in functionality between the two ends, making it impossible to achieve native and Web isomorphism
Here’s how the Navigator component in @hippy/react and @hippy/ react-Web is implemented
1.1 @hippy/react
Routing implementation
In the Navigator component, render displays by instantiating a Hippy instance while listening for Android’s back key
// https://github.com/Tencent/Hippy/blob/312d0d963cac2d8cf60ff97ddd554a01e575cea0/packages/hippy-react/src/components/navig ator.tsx#L125
constructor(props: NavigatorProps) {
super(props);
const { initialRoute } = props;
if (initialRoute && initialRoute.component) {
const hippy = new Hippy({
appName: initialRoute.routeName,
entryPage: initialRoute.component,
});
hippy.regist();
this.routeList[initialRoute.routeName] = true;
}
this.handleAndroidBack = this.handleAndroidBack.bind(this);
}
Copy the code
The page returns by calling native callUIFunction
public pop(option: { animated: boolean }) {
if (this.stack.size > 1) {
const options = [option];
this.stack.pop();
callUIFunction(this.instance, 'pop', options); }}Copy the code
In this way, the two pages cannot communicate with each other or transfer data
1.2 @hippy/react-web
Routing implementation
In contrast to @hippy/react, the Navigator component in @hippy/react- Web has no corresponding implementation function
//https://github.com/Tencent/Hippy/blob/master/packages/hippy-react-web/src/components/navigator.tsx
/* eslint-disable class-methods-use-this */
import React from 'react';
import { formatWebStyle } from '.. /adapters/transfer';
/** * Simply router component for switch in multiple Hippy page. * @noInheritDoc */
class Navigator extends React.Component {
pop() {
// TODO
}
push() {
// TODO
}
render() {
const { style } = this.props;
const newProps = Object.assign({}, this.props, {
style: formatWebStyle(style),
});
return (
<div {. newProps} / >
);
}
}
export default Navigator;
Copy the code
2. Hippy project routing implementation
React-router is used to manage multiple pages and switch between Hippy native and Web pages
2.1 Hippy Router Selection
In React, react-Router is used for page switching, supporting multi-page development. There is also a native version of React -router-native
React-router-native is the native version of the React-Router, but it is based on the more complete Navigator component in React-Native. After analysis and implementation, react-router-native cannot be used directly in Hippy
MemoryRouter in React-Router, a route based on a pure JS implementation, does not need to rely on urls, which makes it applicable to native applications
The following is a description of MemoryRouter
A <Router> that keeps the historyOf your "URL"in memory (does not read or write to the address bar). Useful in tests and non-browser environments like React Native.
Copy the code
Therefore, react-Router can support switching between native and Web pages at the same time for multi-page development
2.1 React-Router used in Hippy
- through
Platform.OS
Determine the current platform - Used in native projects
MemoryRouter
, used in the WebHashRouter
- through
react-router
Switch between multiple pages
Here’s how to use the React-router in Hippy
import React, { Component } from 'react';
import {
StyleSheet,
View,
} from '@hippy/react';
import {
MemoryRouter,
HashRouter,
Route,
} from "react-router-dom";
import routes from './route';
import { ISWEB } from './utils';
export default class App extends Component {
render() {
const Router = ISWEB ? HashRouter : MemoryRouter;
return (
<View>
<Router>
{
routes.map(item => {
return (
<Route key={item.path} exact path={` ${item.path} `} ><item.component meta={item.meta| | {}} / ></Route>); })}</Router>
</View>); }}Copy the code
3. The hippy-React three-terminal isomorphic router is used
3.1 the use ofreact-router
Existing problems
The React-Router can solve multiple page hops in Hippy at a certain level, but it has some problems
- Native switching has no animation and the experience is the same as on the Web
- Unable to use the React-router-transition animation
- Native return operation, directly back to close
hippy
project Link
The process of using the need to pass incomponent
. The reason is thatLink
Component defaulta
The labelAnd thehippy
Do not supporta
The label
// How to use Link in hippy
import { View } from '@hippy/react';
<Link to="/about" component={View}>About</Link>
Copy the code
3.2 Compatibility with page switching
Page switching in A Hippy project In addition to page switching in a Hippy project, there is also interaction with a client or browser
To switch from a Hippy page to a native page on the client, the client needs to provide the support for forwarding to a pseudo protocol. In a Web environment, basic browser capabilities are required. Therefore, compatibility processing is required
There are three main scenarios for page switching in hippy projects
scenario | handling |
---|---|
hippy Within the project |
react-router |
hippy – > native |
Native pseudo protocol support |
hippy – > web page |
window.location orwindow.open |
3.2.1 Compatibility with page switching
- The principle of analysis
The react-router uses the Context to pass functions to jump routes, such as goback and push, to the component
When a component needs to use the React-Router function, it uses the withRouter high-order component to inject the route redirect function into the component
// withRouter usage
// https://reacttraining.com/react-router/web/api/withRouter
import React from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router";
class ShowTheLocation extends React.Component {
static propTypes = { // Declare propTypes to get the router method
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
};
}
const ShowTheLocationWithRouter = withRouter(ShowTheLocation);
Copy the code
Implementation principle of withRouter
// https://github.com/ReactTraining/react-router/blob/402ecabdc94e5aeb657c593d8af200625a09cdfe/packages/react-router/module s/withRouter.js#L11
<RouterContext.Consumer>
{context => {
return (
<Component
{. remainingProps}
{. context}
ref={wrappedComponentRef}
/>
);
}}
</RouterContext.Consumer>
Copy the code
WithRouter’s source code analysis shows that context contains all of the router’s methods for components to use, so you can personalize the context layer according to different platforms
- The solution
Hijacking the context by implementing withRouter’s logic
import { Platform } from '@hippy/react';
import { withHippyHistory } from './history.hippy';
import { withWebHistory } from './history.web';
const ISWEB = Platform.OS === 'web';
const wrapper = ISWEB ? withWebHistory : withHippyHistory
return (
<Component
{. remainingProps}
{. wrapper(context)}
ref={wrappedComponentRef}
/>
);
Copy the code
- In the terminal, override the route jump function to call the natively provided jump method
// history.hippy.js
import { callNativeWithPromise } from "@hippy/react";
import { parsePath } from './util';
const createHook = (history, ) = > {
function push (path, state) {}
function replace () {}
function go () {}
function goBack () {}
function goForward () {}
function open ({ hippyUrl }) {
return callNativeWithPromise('TgclubJsModule'.'callNativeAction', hippyUrl)
}
return { push, go, goBack, goForward, replace, open }
}
export function withHippyHistory (context) {
const { history } = context;
return {
...context,
history: {... history, ... createHook(history) } } }Copy the code
- Provide additional
open
Function to jump to pages that are not part of the project, so that there is no awareness at the business layer.
// history.web.js
const createHook = (history) = > {
function open ({ webUrl, config }) {
if (webUrl) {
window.open(webUrl); }}return { open }
}
export function withWebHistory (context) {
const { history } = context;
return {
...context,
history: {... history, ... createHook(history) } } }Copy the code
Through the transformation of functions in context, unified page switching call method of different platforms. Inside the Wrapper is a special processing for the platform
4. Legacy issues
- Page switching animation
hippy
The in-project page jump ADAPTS the system to return to the previous page actionreplace
Operation requires terminal cooperation and maintenance of page routing stack