preface

The React design idea embodies functional programming in many places. There are multiple ways to combine and reuse components. Here are some of the methods I use in daily development.

High order component

Aside from React, as a JavaScript developer, higher-order functions should have a lot of exposure, such as the common anti-shock and throttling (anti-shock and throttling). If we had to give it a definition, let’s look at the official, high-order component is a function that is passed in to the component and returned as a high-order component

In development, it is common to encounter the need to render the list as empty if the data is empty, if it is a single component need not matter, just add a judgment

render() { if (_.isEmpty(this.prop.dataSource)) { return <Empty />; }... }Copy the code

If there are multiple such judgments, the code repetition rate is high, and at this point we can consider using higher-order components to separate the empty judgments into a higher-order component

const withEmpty = (WrappedComponent) => {
  return (props) => {
    return _.isEmpty(props.dataSource)
      ? <Empty />
      : <WrappedComponent {...props} />;
  }
}
Copy the code

use

render() {
	const WithEmptyUserList = withEmpty(UserList);
	return <WithEmptyUserList dataSource={[]}/>;
}
Copy the code

There are many official instructions in the relevant section, please refer to advanced components

render prop

When calling a component, introduce a function prop that defines how the component should render, not necessarily called Render

const Mouse = ({ render }) => { const [x, setX] = useState(0); const handleMouseMove = (e) => { setX(e.pageX); } return <div onMouseMove={handleMouseMove}> {render({ x })} </div> } class App extends Component { constructor(props) {  super(props) } render() { return ( <Mouse render={({ x }) => <p>{x}</p>} /> ) } }Copy the code

The Mouse component records the x coordinates of the movement, and the rendering is handed over to the Render function passed in by the parent component.

Child Component

This is common with react common components such as Context and react-router

// Context render() { return <Context.Consumer> {(props) => {... }} </Context.Consumer> }Copy the code
// React-router render() { return ( <HashRouter> <Route path='/' render={() => '/'} /> <Route path='/home' render={() =>  '/home'} /> </HashRouter> ) }Copy the code

There are many common components on the market with similar encapsulation, as well as several components such as ANTD

This implements an ultra-lazy version of the React-Router, hashRouter, and Route sections

const Context = createContext(); const HashRouter = ({ children }) => { const [match, setMatch] = useState(_.replace(location.hash, '#', '')); useEffect(() => { const handleHashChange = (value) => { setMatch(_.replace(location.hash, '#', '')); } window.addEventListener('hashchange', handleHashChange); return () => window.removeEventListener('hashchange', handleHashChange); } []); return <Context.Provider value={{ match }}> {children} </Context.Provider> } const Route = ({ path, render }) => { return <Context.Consumer> {({match}) => { if (match === path) { return render() }; return null; }} </Context.Consumer> } class App extends Component { constructor(props) { super(props) } render() { return ( <HashRouter> <Route path='/' render={() => '/'} /> <Route path='/home' render={() => '/home'} /> </HashRouter> ) } }Copy the code

The key step or two

  • HashRouterListen for route changes and preserve themhashValue, render allchildren
  • RouteCompare the currenthashAnd the incomingpath, returns if correct

The real React-Router has a lot more judgment than this one. For example, it only performs the congruent operation on the hash value. In fact, the judgment of Route is much more complicated

{props.match
  ? children
    ? typeof children === "function"
      ? __DEV__
        ? evalChildrenDev(children, props, this.props.path)
        : children(props)
      : children
    : component
    ? React.createElement(component, props)
    : render
    ? render(props)
    : null
  : typeof children === "function"
  ? __DEV__
    ? evalChildrenDev(children, props, this.props.path)
    : children(props)
  : null}
Copy the code

Recommended to read the relevant source code

conclusion

A lot of the code in this article uses hook. All versions below 16.8 May have problems. The above summary is based on several reuse methods commonly used in my daily work, welcome to discuss

🏆 nuggets technical essay | double festival special articles