使用React 手写一个 useTitle

397 阅读1分钟

你在工作中,有没有遇到过每个一个页面,然后我们每个页面的title都是要设置不同的标题?

接下来我们手写一个自定义hooks 来解放我们的双手。

我们先进行梳理需求。

  1. 我们可以刚刚进页面的时候初始化一个title。
  2. 我们有可能在组件卸载的时候恢复到原来的title。

我们需求梳理清楚了,就可以进行代码的编写了。 代码如下:

import { useEffect, useRef } from 'react';
/**
 *  获取当前环境是否是浏览器环境
 * @returns boolean
 */
function getIsBrowser(): boolean {
  const isBrowser = !!(
    typeof window !== 'undefined' &&
    window.document &&
    window.document.createElement
  );
  return isBrowser;
}

interface Options {
  restoreOnUnmount?: boolean;
}

/**
 * @param title 
 * @param options 
 */

function useTitle(title: string, options: Options = { restoreOnUnmount: false }) {
  // 我们需要先拿到原来的title 进行保存起来 我们要判断当前环境是不是浏览器 
  const isBrowser = getIsBrowser();
  const titleRef = useRef(isBrowser ? document.title : '');

  useEffect(() => {
    document.title = title;
  },
    [title]);

  // 组件卸载 
  useEffect(
    () => () => {
      if (options.restoreOnUnmount) {
        document.title = titleRef.current;
      }
    },
    [],
  );
}
 export default function IndexPage() {
  // 使用
  useTitle('11111');
  return (
    <div>
    </div>
  );
}

既然我们都使用hooks 比如有一些操作是可以进行在进行封装的,比如我们封装的每个hooks可能在组件卸载的时候进行做一些操作

完整版本

    import { useEffect, useRef, useState } from 'react';
/**
 * 卸载hooks
 */
function useUnload(fn: () => void) {
  if (typeof fn !== 'function') {
    console.error(`你传的fn类型如下: ${typeof fn}`);
    return;
  };
  const fnRef = useRef(fn);
  useEffect(() => () => { fnRef.current() }, []);
};

/**
 *  获取当前环境是否是浏览器环境
 * @returns boolean
 */
function getIsBrowser(): boolean {
  const isBrowser = !!(
    typeof window !== 'undefined' &&
    window.document &&
    window.document.createElement
  );
  return isBrowser;
}
interface Options {
  restoreOnUnmount?: boolean;
}
/**
 * @param title 
 * @param options 
 */
function useTitle(title: string, options: Options = { restoreOnUnmount: false }) {
  // 我们需要先拿到原来的title 进行保存起来 我们要判断当前环境是不是浏览器 
  const isBrowser = getIsBrowser();
  const titleRef = useRef(isBrowser ? document.title : '');

  useEffect(() => {
    document.title = title;
  },
    [title]);

  useUnload(() => {
    if (options.restoreOnUnmount) {
      document.title = titleRef.current;
    }
  });
};