1. Higher-Order Functions -- Functions that can manipulate other functions.

3 categories:

  • take functions in as arguments
  • return functions
  • both

1.1. Take functions as arguments

The first category of higher-order functions are functions that expect other functions as arguments. Array.map, Array.filter, and Array.reduce all take functions as arguments. They are higher-order functions.

In the following example, we create an invokeIf callback function that will test a condition and invoke on callback function when it is true and another callback function when that condition is false:

const invokeIf = (condition, fnTrue, fnFalse) => (condition ? fnTrue() : fnFalse());

const showWelcome = () => console.log('Welcome!!!');

const showUnauthorized = () => console.log('Unauthorized!!!');

invokeIf(true, showWelcome, showUnauthorized); // "Welcome"
invokeIf(false, showWelcome, showUnauthorized); // "Unauthorized"

invokeIf expects two functions: one for true, and one for false. This is demonstrated by sending both showWelcome and showUnauthorized to invokeIf. When the condition is true, showWelcome is invoked. When it is false, showUnauthorized is invoked.

1.2. return functions - currying

Higher-order functions that return other functions can help us handle the complexities associated with asynchronicity in JavaScript. They can help us create functions that can be used or reused at our convenience.

Currying is a functional technique that involves the use of higher-order functions. Currying is the practice of holding on to some of the values needed to complete an operation until the rest can be supplied at a later point in time. This is achieved through the use of a function that returns another function, the curried function.

The following is an example of currying. The userLogs function hangs on to some information (the username) and returns a function that can be used and reused when the rest of the information (the message) is made available. In this example, log messages will all be prepended with the associated username. Notice that we’re using the getFakeMembers function that returns a promise.

const userLogs = (userName) => (message) => console.log(`${userName} -> ${message}`);

const log = userLogs('grandpa23');
log('attempted to load 20 fake members');

getFakeMembers(20).then(
  (members) => log(`successfully loaded ${members.length} members`),
  (error) => log('encountered an error loading members'),
);

// grandpa23 -> attempted to load 20 fake members
// grandpa23 -> successfully loaded 20 members

// grandpa23 -> attempted to load 20 fake members
// grandpa23 -> encountered an error loading members

userLogs is the higher-order function. The log function is produced from userLogs, and every time the log function is used, “grandpa23” is prepended to the message.

1.3. Higher Order Component

This is an example in react.fundamentals

/**
 * HOC for data fetching
 */
import React from 'react';

const DataComponent = (ComposedComponent, url) =>
  class NewComponent extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        data: [],
        loading: false,
      };

      this._getData = this._getData.bind(this);
      this.fetchByParam = this.fetchByParam.bind(this);
    }

    _getData(param = {}) {
      // 如果 param 传入 url 参数则根据此 url 进行查询,不然根据顶层传入 url 参数查询
      if (param.url) {
        url = param.url;
      }

      this.setState({ loading: true });

      fetch(url)
        .then((response) => response.json())
        .then((data) => {
          if (this._isMount) {
            this.setState({ loading: false, data: data.items, param });
          }
        });
    }

    fetchByParam(param) {
      this._getData(param);
    }

    componentWillMount() {
      this._getData();
    }

    componentDidMount() {
      this._isMount = true;
    }

    componentWillUnmount() {
      this._isMount = false;
    }

    // only for solution 4. 返回的NewComponent作为子组件,父组件状态作为props传到子组件
    // 父组件状态改变的时候,自组件props发生改变,该方法触发,根据传入的param进行数据查询
    componentWillReceiveProps(nextProps) {
      // console.log(`nextProps`, nextProps.param);
      // call getData only when param props changed. Other props change will enter componentWillReceiveProps too, but we don't want to fetch data
      if (nextProps.param) {
        this._getData(nextProps.param);
      }
    }

    render() {
      return (
        <div className="data-component">
          {this.state.loading ? (
            <p
              style={{
                textAlign: 'center',
                fontSize: '20px',
              }}
            >
              Loading...
            </p>
          ) : (
            <ComposedComponent {...this.state} {...this.props} fetchByParam={this.fetchByParam} />
          )}
        </div>
      );
    }
  };

export default DataComponent;
Copyright © Guanghui Wang all right reserved,powered by GitbookFile Modified: 2019-08-25 13:56:34

results matching ""

    No results matching ""