• Pickup-Only Stores Are the Future for Fast Food and Drinks

    In Manhattan, I found a Starbucks that was pick-up only and you had to order online. It had no seating, just a counter to pick up your order. It didn’t even have a cash register.

    In the COVID-19 world, this is the future of fast-food. No one wants to stand around while their order is being made on the spot (for health reasons and boredom). We’ve all been trained to order food online. Pick-up only stores makes perfect sense.


  • Gracefully Fetch API Data With React and TypeScript

    Fetching API data from a component using React requires handling loading, error, auth, and success states. This makes fetching data difficult to abstract and integrate well into the hooks in a natural way. Further, it’s easy to make mistakes calling function components with the wrong props only to find out at run time.

    To solve this, we need to implement three things:

    1. A hook that calls the API and returns data representing the status (loading, error, success, etc).
    2. A higher-order component that handles rendering API states (e.g. a loading indicator) and maps data from a successful API call to a passed in component’s props.
    3. A component for displaying data from the API without having to duplicate loading states and errors.

    See also

    Implementing a useApi hook

    We want to represent our API call with data instead of callbacks and managing state manually. To do that, we’ll create our own hook that makes an API call, handles auth errors (like refreshing an auth token), and returning data from the API response.

    Here’s an example that (ab)uses the useEffect hook to make an API call and automatically refresh tokens and retry if there was a recoverable auth error.

    Note: refreshToken would be some other fetch call to acquire a new API access tokenโ€”a common scenario for token based authentication in a web app.

    export enum ApiStatus {
      // API request is being made
      Loading,
      // API call was successful
      Success,
      // API call resulted in an unauthorized error even after attempting
      // a token refresh
      ErrorUnauthorized,
      // API resulted in an error
      Error,
      // The initial request failed and we are attempting to refresh an
      // access token
      RefreshingToken,
      // We have new access token and will attempt to make a request
      // again. Note: if the retry fails the status will be `Error`.
      Retrying,
    }
    
    interface IApiData {
      status: ApiStatus
      error: any,
      data: any,
    }
    
    /*
    Hook for fetching data from the backend API. Returns an `IApiData`
    object. See `ApiStatus` for which states need to be handled.
    
    API calls that fail due to an unauthorized error (expired token) are
    automatically retried after attempting to refresh an access token.
    
    To do that (and avoid infinite loops) this is essentially a state
    machine that supports the following ApiStatus transitions:
      Loading -> Success
      Loading -> Error
      Loading -> RefreshingToken
      RefreshingToken -> Retrying
      RefreshingToken -> Error
      RefreshingToken -> ErrorUnauthorized
      Retrying -> Success
      Retrying -> Error
      Retrying -> ErrorUnauthorized
    */
    export const useApi = (url: string, body = {}) => {
      const [retryToggle, setRetryToggle] = useState(false);
      const [data, setData] = React.useState<IApiData>({
        status: ApiStatus.Loading,
        error: null,
        data: null,
      });
    
      React.useEffect(() => {
        if (data.status === ApiStatus.RefreshingToken) {
          // Try refreshing the access token and retrying the request
          console.log('Attempting to refresh access token')
          myRefreshTokenFn().then(() => {
            setData({
              status: ApiStatus.Retrying,
              data: null,
              error: null,
            });
    
            // Trigger a retry
            setRetryToggle((i: boolean) => !i);
          }).catch((err: MyRefreshTokenError) => {
            // Handle errors and set the the API status accordingly
            if (err === MyRefreshTokenError.Expired) {
              setData({
                status: ApiStatus.ErrorUnauthorized,
                data: null,
                error: err
              });
            } else {
              setData({
                status: ApiStatus.Error,
                data: null,
                error: err
              });
            }
          });
          return;
        }
    ;
        const authToken = myAuthTokenFn();
        const request: RequestInit = {
          method: 'POST',
          body: JSON.stringify(body),
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${authToken}`,
          },
        }
    
        fetch(url, request)
          .then((response) => {
            if (!response.ok) {
              throw Error(response.statusText);
            }
            return response.json()
          })
          .then((data) => {
            setData({
              status: ApiStatus.Success,
              error: null,
              data
            });
          })
          .catch((err: Error) => {
            // The only way this could happen is if something is broken
            // with the refresh token process (e.g. we get a new access
            // token, but it's invalid due to some coding error). We
            // explicitely disallow going from Retrying -> RefreshingToken
            // in order to avoid a potential infinite loop.
            if (data.status === ApiStatus.Retrying) {
              console.log('Unauthorized. Not retrying:', data.status);
              setData({
                status: ApiStatus.ErrorUnauthorized,
                data: null,
                error: err
              });
              return;
            }
    
            switch (err.message) {
              // Recover from an unauthorized error by triggering a token
              // refresh.
              case 'Unauthorized':
                setData({
                  status: ApiStatus.RefreshingToken,
                  data: null,
                  error: err
                });
    
                // Trigger the effect again
                setRetryToggle((i: boolean) => !i);
                break;
              default:
                setData({
                  status: ApiStatus.Error,
                  data: null,
                  error: err
                });
            }
          });
        // This dependency allows us to re-run the effect whenever this
        // value changes.
      }, [retryToggle]);
    
      return data;
    }
    

    Here’s how to use it in a component:

    export const FooComponent: FunctionComponent = () => {
      let { status, error, data } = useApi(`https://myapi/resource`);
    
      return (
        ...
      )
    }
    

    However, we now need to handle all possible variants of ApiStatus which would result in a large amount of boilerplate code to render things like loading states and logging out because of an auth error.

    Higher-order component

    To reduce the boilerplate we’ll introduce a higher order component that handles all the API states and calls or component that needed the API data in the first place.

    type ApiStatusHandlerProps<T> = {
      status: ApiStatus,
      error: Error,
      data: any,
      component: FunctionComponent<T>,
    }
    
    /*
       Higher order component that handles API request states for loading,
       error, complete. This should be paired with the `useApi` hook.
    
       Generic type `P` is the props type to pass to `FunctionComponent`
       specified by `component` if the API request is successful. This
       provides type safety because you will get a type error if the props
       type doesn't match the component.
     */
    export function ApiStatusHandler<P>(
      { status, data, component }: ApiStatusHandlerProps<P>
    ): React.ReactElement<P> | null {
      switch (status) {
        case ApiStatus.ErrorUnauthorized:
          /* Handle logging out */
          return (<p>Logging you out </p>);
        case ApiStatus.Error:
          /* Handle displaying an error */
          return (<p>Big error!</p>);
        case ApiStatus.Loading:
        case ApiStatus.Retrying:
        case ApiStatus.RefreshingToken:
          /* Show loading */
          return (<p>Loading</p>);
        case ApiStatus.Success:
          /* Call our component with data from the API response */
          return component(data);
    
        // Compile time error if we haven't covered all ApiStatus variants
        default: ((x: never) => { throw new Error(status + " was unhandled."); })(status);
      }
    }
    

    Now we can use the ApiStatusHandler like this:

    export const FooComponent: FunctionComponent = () => {
      let { status, error, data } = useApi(`https://myapi/resource`);
    
      return (
        <ApiStatusHandler<BarProps> status={status} error={error} data={data} component={BarComponent} />
      )
    }
    

    A component for rendering content from the API call

    The component called by ApiStatusHandler gets passed in props from the API response. Since ApiStatusHandler is parameterized by the component’s prop type we get some additional type safetyโ€”you can’t accidentally call component with the wrong props or you’ll get a compile time error.

    (In practice you might also want to have a function to translate the API response data to props)

    type BarProps = {
        status: string
    }
    
    const BarComponent: FunctionComponent<BarProps> ({status}) => (
      <p>{status}</p>
    )
    

  • Nobody Grades an Economist

    The reason you shouldn’t rely on what economists say to make decisions (for example in financial decisions) is because nobody grades an economist. As Howard Marks puts it, “Economists are like portfolio manager who don’t mark to market.” In other words, a source of predictions is only useful if it is reliably correct, but there is no way to know that about an economist because they don’t keep score.

    See also:

    • Naval Ravikant often says you shouldn’t trust someone who doesn’t have “skin in the game”

  • We Find What We Seek, What We Projected

    Jiddu Krishnamurti recounts a story about a man who has in solitude and meditated for 25 years only to recognize that it was a waste. Krishnamurti’s advice to this man was merely “don’t seek” because what you find when you search is what you projected.

    In previous talks, he discusses his dislike for meditation and mindfulness because it tends to have a motive behind itโ€”a desire to achieve something or fulfill a promise someone made. To really see there needs to be no motive at all.

    See also:

    • The underlying desire and motive for meditation is another form of the illusory self

  • Figure Out What's Wrong With a Step in a Funnel by Looking at the Previous Step

    When you are trying to figure out why a particular step in the funnel isn’t working, start by looking at the previous step. What happened in previous step that would have solved the problem you’re seeing in the next step? In sales, this is usually because you didn’t set the stage for the next stage properly.

    For example, if you are having trouble closing a sale, look at the demo you did in the previous stepโ€”it should naturally lead to a sale if it was really was the solution to a burning problem the buyer has. Then look at the step prior to that and it could be that you didn’t understand their burning problem or enough information to describe the solution in their terms.

    See also:


  • Decision Fatigue Leads to Bad Decision Making

    It takes effort to make decisions and when confronted with numerous decisions to make, people get fatigued. These aren’t just big decisions (what should I do with my life?), but also small ones (what should I wear? what should I eat for dinner). This impairs a person’s ability to make further decisions (or avoid them).

    However, it’s unclear whether this is a consistent phenomenon. Research by Carol Dweck reveals decision fatigue primarily affects people who believe willpower runs out quickly. Decision fatigue is also related to studies on ego depletion, which has since been debunked.


  • Al Smith Was a Poor and Uneducated Tammany Man Who Rose to Be the Governor of New York

    Al Smith was a poor Irish-American who grew up in the Fourth Ward of New York City (Lower East Side). He became a Tammany Hall loyalist and henchman, but became so well liked (by Tammany and the people of his district) that he was elected to the State Assembly.

    Not knowing anything about legislation and bills, every night he would read each bill. He would pay for transcripts of the days session to read later so he could try to understand it. He would sit in on committees that he wasnโ€™t a part of. He then mastered it. Combined with his likable character, talent for oration, and now an in-depth understanding of how legislation worked and itโ€™s problems he quickly became effective and championed reform while becoming the assembly speaker.

    He then pushed for the local Tammany democrats to change course and embrace progressivism. They acquiesced and it opened the door for a new kind of candidateโ€”the kind that made Al Smith the governor of New York where he led a progressive agenda.

    See also: