vite + react + ts рукопашный проект, серия 2 (актуальная глава)

внешний интерфейс React.js Vite

портал

предисловие

  • Эта актуальная боевая статья, которую я много раз переделывал, изначально добавлял много сложных пакетов, но она очень недружелюбна для студентов-новичков в react+ts, потому что ее нелегко понять Поэтому я сокращаю, сокращаю и сокращаю, стараюсь писать так, чтобы все могли понять, стараюсь использовать краткий язык, чтобы выразить, какие функции мы хотим сделать, сначала легко, а затем сложно.

  • Инкапсуляция сложных функций будет подробно объяснена в следующей серии статей, пошаговое углубленное изучение, Большая часть кода в проекте снабжена подробными комментариями, надеюсь, вы не запутаетесь, потому что когда я был новичком, я искал опенсорсные проекты на github, их много Проект хорошо упакован, но Xiaobai очень запутался и должен долго смотреть его, поэтому я постараюсь подробно объяснить в этом уроке.Согласно документации, проект может выполняться, а аннотации подробно написано, а затем сотрудничайте с прямой трансляцией, чтобы рассказать о ней.

  • ts Не думайте, что это сложно, зайдите на официальный сайт, чтобы увидеть основные способы использования, вы можете это сделать, просто проверьте грамматику, которую вы не понимаете, просто используйте ее несколько раз.

  • То же самое верно и для реакции, не будьте невежественны и нуждайтесь в большой практике кода. Если не понимаете, спросите, а если не знаете, проверьте.

  • В этой статье в основном пишут

    • Использование поддельных данных json-сервера

    • Простое использование интерфейса запроса

    • Простое использование маршрутизации

    • Некоторые простые данные глобальной конфигурации

    • международное использование

    • Инкапсуляция простых общих компонентов

фиктивные данные json-сервера

  • yarn add json-server -D

  • в терминале

    mkdir mock
    cd mock
    touch db.json
    
  • Добавьте скрипты в package.json

    "mock": "json-server mock/db.json --port 3008"
    
  • Затем запустите команду yarn mock, чтобы успешно получить доступ к данным интерфейса, которые мы настроили в db.json в консоли.

инкапсуляция запроса

Примечание: process.env следует заменить на import.meta.env.

  • Глобальные общедоступные файлы конфигурации будут размещены в файле config.ts в корневом каталоге.В настоящее время в начале проекта имеется лишь небольшой объем информации о конфигурации.
 /**
 * 当前环境变量
 */
// process.env 在vite中不能用
// export const whyEnv = import.meta.env.VITE_REACT_URL || "";
/**
 * 接口地址
 * @description env 可为主要环境或自定义地址
 */
export const apiAddress = "http://localhost:3008/";

/**
 * 开发代理前缀
 */
export const proxyApi = "/api";

/**
 * 接口前缀
 * 判断环境,是否需要使用前缀
 * 生产环境不需要代理,同时本地配置的代理在生产环境也是不能用的
 */
export const urlPrefix = process.env.NODE_ENV === "development" ? proxyApi : "";

  • Библиотека umi-request, используемая в проекте, на данный момент я настроил очень мало вещей, таких как обработка ошибок, обработка промежуточного ПО и т. д. Я ее удалил, не стал так усложнять в начале.
   // utils/request.ts

 /**
 * request 网络请求工具
 * 更详细的 api 文档: https://github.com/umijs/umi-request
 */
import umiRequest, { extend } from "umi-request";
import { urlPrefix } from "../config";

// 使用前缀,配合本地代理
export const whyRequest = extend({
  prefix: `${urlPrefix}`,
});

export default umiRequest;
  • Определите интерфейс: необходимо заранее сообщить входные параметры и формат выходных параметров с последним разделом.В сочетании с подсказкой типа ts вы можете напрямую видеть свойства, определенные интерфейсом, при вызове в других местах, что очень удобно.
/**
* 登陆请求数据类型
*/
export interface ILogin {
  userName: string;
  pwd: string;
}

/**
* 返回数据类型
* 要提前和后段定义好类型,等接口写完直接替换地址就好了
*
*/
export interface ILoginData {
code: number;
message: string;
token: string;
}

/**
* 登陆接口
* @param params
  */
  export const loginApp = (params: ILogin): Promise<ILoginData> => {
  return whyRequest.get("/login", params);
  };
  • Он очень прост в использовании, вызовите его напрямую, а затем мы будем сотрудничать с useRequest() в ahooks.
 loginApp({ userName: "why", pwd: "123" }).then((res) => {
     if (res.code === 200) {
       history.push("/home");
     } else {
       message.error("用户名或密码错误!");
     }
   });

международная конфигурация

  • yarn add react-intl -D
  • Для интернационализации мы используем react-intl, а также совместимы с китайским и английским языками antd и другими плагинами.Когда мы переключаем языки, библиотека плагинов также должна быть напрямую переключена на соответствующий язык, что также очень удобно. удобно настроить.
  • переходим непосредственно к коду
// 引入创建语言,国际化容器,暂时我们只需要用这两个就可以实现的我们目前的功能
import { createIntl, IntlProvider } from "react-intl";
// 我们需要引入antd 的国际化的配置
import antdEnUS from "antd/lib/locale/en_US";
import antdZhCN from "antd/lib/locale/zh_CN";
// 这是我们项目中中英文的配置,
import enLn from "./components/ln-en";
import zhLn from "./components/ln-zh-cn";
···核心代码
/**
* 包裹了默认 locale 的 Provider
* LocaleProvider 需要在App.tx使用,包装整个项目
* @param props
* @returns
  */
  export const LocaleProvider: React.FC = (props) => {
  return <IntlProvider locale={getLocale()}>{props.children}</IntlProvider>;
  };
/**
 * 获取当前的 intl 对象,可以在 node 中使用
 * @param locale 需要切换的语言类型
 * @param changeIntl 是否不使用 g_intl
 * @returns IntlShape
 */
  const getIntl = (locale?: string, changeIntl?: boolean) => {

  // 如果全局的 g_intl 存在,且不是 setIntl 调用
  if (gIntl && !changeIntl && !locale) {
  return gIntl;
  }
  // 如果存在于 localeInfo 中
  if (locale && localeInfo[locale]) {
  return createIntl(localeInfo[locale]);
  }

// 使用默认语言
if (localeInfo[defaultLanguage])
return createIntl(localeInfo[defaultLanguage]);
// 使用 zh-CN
if (localeInfo["zh-cn"]) return createIntl(localeInfo["zh-cn"]);
  // 抛错
if (!locale || !!localeInfo[locale]) {
  throw new Error(
  "The current popular language does not exist, please check the locales folder!"
  );
  }
// 如果还没有,返回一个空的
return createIntl({
locale: "zh-cn",
messages: {},
});
};
/**
* 语言转换
* @param descriptor
* @param values
  */
  export const formatMessage = (
  descriptor: MessageDescriptor,
  values?: Record<string, any>
  ) => {
  if (!gIntl) {
  setIntl(getLocale());
  }
  return gIntl.formatMessage(descriptor, values);
  };
  • используется на странице

    1. Нам нужно настроить контрастность китайского и английского языков в соответствующем файле ts.

    // 在locale 文件下配置中文对照
    export default {
    frontEnd: "Work hard on the front end",
    switchLan: "Chinese-English shift",
    switchToEn: "switch to chinese",
    switchToCh: " switch to english",
    localLan: "The internationalization of this project is   based on",
    };
    // 配置英文对照
    export default {
    frontEnd: "前端要努力",
    switchLan: "中英文切换",
    switchToEn: "切换到中文",
    switchToCh: "切换到英文",
    localLan: "本项目国际化基于",
    };
    

    2. На странице мы напрямую вызываем метод formatMessage().

/**
 * 国际化页面
 * @constructor
 */
const LocalePage: React.FC = () => {
  // 这使用的是useState,其实这里是完全不需要的
  const [value, setValue] = React.useState(
    localStorage.getItem("why__locale") || "zh-cn"
  );
  // 切换多语言
  const onChange = (e: RadioChangeEvent) => {
    setValue(e.target.value); //在这里是没有作用的代码
    setLocale(e.target.value); // 调用切换多语言方法,然后刷新页面
  };
  return (
    <Card title={formatMessage({ id: "switchLan" })} style={{ width: "500px" }}>
      <Radio.Group onChange={onChange} value={value}>
        <Radio value={"zh-cn"}>{formatMessage({ id: "switchToEn" })}</Radio>
        <Radio value={"en"}>{formatMessage({ id: "switchToCh" })}</Radio>
      </Radio.Group>
      <div className={styles.localLan}>
        {formatMessage({ id: "localLan" })}react-intl
      </div>
    </Card>
  );
};
  • Интернационализированные страницы

image.png

маршрутизация

  • реагирующая маршрутизация см. это

  • Система маршрутизации React сильно отличается от Vue. Перед навигацией по маршрутизации нет хука. Чтобы настроить аутентификацию при входе, вы должны настроить ее самостоятельно. В сочетании с токеном,

  • Целью маршрутизации в нашем проекте является поддержка динамической маршрутизации, разрешений маршрутизации и извлечения конфигурации.В настоящее время это самый простой, голый

image.png

инкапсуляция общедоступного компонента

  • Как мы инкапсулируем публичный компонент?

    1. Компоненты, которые необходимо использовать в нескольких местах проекта.

    2. Компоненты, не связанные с бизнесом, публичные компоненты, связанные с бизнесом

    3. Всеми состояниями можно управлять извне, а их поведение контролируется входящим реквизитом вместо того, чтобы обнажать его внутреннюю структуру.

    封装良好的组件隐藏其内部结构,并提供一组属性来控制其行为。
    
    隐藏内部结构是必要的。其他组件没必要知道或也不依赖组件的内部  结构或实现细节
    
  • Единый каталог в нашем проекте, в основном для удобства

  • содержание:image.png

    • index.tsx — основной файл записи

    • index.md — это пример использования компонента, необходимые комментарии к коду, и необходимо четко рассказать другим, как использовать этот общий компонент

    • image.png

Как использовать значки шрифта iconfont

  • Инкапсулируйте значок, в основном сотрудничайте с antd createFromIconfontCN, чтобы напрямую ввести значок шрифта в iconfont, что очень удобно.
  • Как показано на рисунке ниже, войдите непосредственно на веб-сайт iconfont, чтобы сгенерировать соответствующий файл js, просто используйте его непосредственно в проекте, это очень просто.

  // 简单来说

  // 这里可以根据各属性动态添加,如果属性值为true则为其添加该类名,

  // 如果值为false,则不添加。这样达到了动态添加class的目的

   <FontIcon
      className={classNames(
        {
          [styles.large]: size === "large", // 返回为true使用css .large,下方同理
          [styles.normal]: size === "normal",
          [styles.small]: size === "small",
          [styles.disabled]: disabled,
        },
        className
      )}
      {...restProps}
    />
  • Использование React.FC 1.React.FC — это функциональный компонент, который является универсальным типом, используемым в TypeScript.FC — это аббревиатура от FunctionComponent.На самом деле React.FC можно записать как React.FunctionComponent:
const App: React.FunctionComponent<{ message: string }> = ({ message }) => (
  <div>{message}</div>
);

2.React.FC включает общий тип PropsWithChildren без явного объявления типа props.children. React.FC является явным для возвращаемого типа, в то время как обычная версия функции является неявной (в противном случае требуется дополнительный комментарий).

3. React.FC предоставляет статические свойства с проверкой типов и автозаполнением: displayName, propTypes и defaultProps (примечание: у defaultProps будут некоторые проблемы с React.FC).

4. Когда мы используем React.FC для написания компонентов React, мы не можем использовать setState, вместо этого мы используем Hook API, такие как useState() и useEffect.

Инкапсулировать общедоступные компоненты значка

  // IconType继承React.HTMLAttributes的属性,然后IconType,就拥有了其可被外界访问的属性
  export interface IconType extends React.HTMLAttributes<any> {
  // type 必有属性,如果使用的时候没有静态检查是,会提示错误,类型不匹配,使用ts的好处,静态类型检查非常nice
  // 报错如下:TS2741: Property 'type' is missing in type '{}' but required in type 'IconType'.  index.tsx(7, 3): 'type' is declared here.
  type: string;
  // 图标尺寸,默认 normal
  size?: "small" | "normal" | "large" | null; // 可选属性,size后面加上?
  // 是否禁用
  disabled?: boolean;
}
// createFromIconfontCN 返回一个组件
const FontIcon = createFromIconfontCN({
  // 请给新图标一个合适的驼峰命名,并保证单词正确
  scriptUrl: "//at.alicdn.com/t/font_955172_ymhvgyhjk.js",
});

const Icon: React.FC<IconType> = ({
  className,
  size = "normal",
  disabled,
  ...restProps
}) => {
  // 我们使用classNames 这个插件动态渲染icon的状态,size,disabled等等
  return (
    <FontIcon
      className={classNames(
        {
          [styles.large]: size === "large",
          [styles.normal]: size === "normal",
          [styles.small]: size === "small",
          [styles.disabled]: disabled,
        },
        className
      )}
      {...restProps}
    />
  );
};
// 思考题:这个地方需要用,react.memo吗?
export default React.memo(Icon);

  • Использование (на скриншоте есть общедоступные компоненты iconSelect, в этой статье объяснять не буду)

image.png

Эпилог

  • первая серия практических проектов vite + react + ts (конфигурация проекта)
  • адрес github (github обновляется быстрее, чем документ, и к документу нужно добавить много комментариев)гитхаб-адрес
  • Если у вас есть какие-либо вопросы, вы можете подать проблему или добавить блогер: lisawhy0706
  • В следующей статье будут в основном объясняться некоторые сложные компоненты
    • Улучшить функционал в проекте
    • Обработка общедоступной конфигурации
    • Инкапсуляция пользовательских хуков
    • Как разработать разрешения для проекта, включая разрешения на маршрутизацию, разрешения на уровне кнопок