如何使用上下文API在React中创建自定义警报组件
#javascript #网络开发人员 #编程 #react

您是否必须实现一个需要您提示用户响应的功能(例如,在删除项目之前的确认消息)?还是您想拥有一个“很棒的”设计师,该设计师设计了一个很棒的组件,以通知用户特定的操作?或出于您决定阅读本文的其他一百个原因。 在本文中,我们将实施一个自定义警报组件,以提示用户执行操作或使用上下文API通知用户。

先决条件

本教程利用以下语言/技术,并要求您对其使用的基本知识。

  • 打字稿
  • reactjs(用create-react-app boottrant)
  • CSS

配置

潜入创建警报组件,您需要做的第一件事就是设置代码库。由于我们将使用ReactJ,因此您可以使用任何可用的React库,但是出于本教程的目的,我们将使用koude0

引导React Application进行引导。

构造代码库。

设置代码库后,您将继续构建代码库,如下。

  • src文件夹中创建一个名为components的文件夹。
  • 在组件文件夹中,创建一个名为Alert的新文件夹。
  • 在警报文件夹中,创建一个名为Alert.tsx的文件。

复制以下代码并粘贴在您的nerver.tsx文件

// the component UI will live in this file

const Alert = () => {
  return (
    <></>
  );
};

export default Alert;

  • 接下来,您在名为AlertProvider.tsx的警报文件夹中创建一个文件。 在AlertProvider.tsx文件中,粘贴以下代码。
import { createContext, useRef, useState } from "react";

export const AlertContext = createContext();

const AlertProvider: React.FC<{ children: React.ReactNode }> = ({
  children,
}) => {
  return (
    <AlertContext.Provider
      value={}
    >
      {children}
    </AlertContext.Provider>
  );
};

export default AlertProvider;

接下来,您在Alert文件夹中创建一个名为index.tsx的文件。
index.tsx文件中,粘贴以下代码;

在这里,您正在为警报组件和孩子们订阅上下文更改的警报上下文创建包装器。

import { useContext } from "react";
import AlertProvider, { AlertContext } from "./AlertProvider";
import Alert from "./Alert";

// create hook to be used globally to toggle alert component.
export const useAlert = () => useContext(AlertContext);

const AlertContainer: React.FC<{ children: React.ReactNode }> = ({
  children,
}) => {
  return (
    <AlertProvider>
      <Alert />
      {children}
    </AlertProvider>
  );
};

export default AlertContainer;

在输入文件中注册警报上下文

现在您已经为警报组件创建了上下文,您将通过更新条目文件在全球注册上下文。对于本教程,您将更新src/index.tsx文件。如果您使用的是其他框架,则您的条目文件可能会有所不同(对于NextJ,该条目将是/pages/_app.tsx

使用以下代码更新src/index.tsx文件。

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import AlertContainer from "./components/Alert"; // import the AlertContainer

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <React.StrictMode>
    {/* Wrap your application with the Alert context wrapper you created in `/components/Alert/index.tsx' */}
    <AlertContainer>
      <App />
    </AlertContainer>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

实现警报组件的功能。

现在您已经完成了设置,现在您将为您的警报组件实现功能。
在本教程中,您将实现的主要功能是

  • Open alert component:这将涵盖您组件将呈现的不同状态。作为通知者或作为求职者。
  • Close alert component:这将涵盖从用户视图中删除警报组件并将上下文状态删除为默认。

现在开始更新src/components/AlertProvider.tsx文件。

首先,您需要声明将在功能中使用的类型。
所以您的文件看起来像这样;

import { createContext, useRef, useState } from "react";

// type for notification object
interface IAlertNotification {
  title: string;
  message: string | React.ReactNode;
  delay?: number;
  autoClose?: boolean;
  inputProps?: React.HTMLAttributes<HTMLInputElement>;
  actions?: {
    text: string;
    callback?: (arg: any) => void;
    props?: React.HTMLAttributes<HTMLButtonElement>;
  }[];
}

// the types for methods and variable available in your alert context
interface IAlertContext {
  alert: (args: IAlertNotification) => void;
  alertShown?: boolean;
  notification?: IAlertNotification;
  close: () => void;
}

// intialise default methods for context.
export const AlertContext = createContext<IAlertContext>({
  alert: () => {},
  close: () => {},
});

const AlertProvider: React.FC<{ children: React.ReactNode }> = ({
  children,
}) => {
  return (
    <AlertContext.Provider
      value={}
    >
      {children}
    </AlertContext.Provider>
  );
};

export default AlertProvider;

接下来,您将创建必要的变量和方法来显示和隐藏警报组件。
因此您的文件看起来像这样:

import { createContext, useRef, useState } from "react";

// type for notification object
interface IAlertNotification {
  title: string;
  message: string | React.ReactNode;
  delay?: number;
  autoClose?: boolean;

  inputProps?: React.HTMLAttributes<HTMLInputElement>;
  actions?: {
    text: string;
    callback?: (arg: any) => void;
    props?: React.HTMLAttributes<HTMLButtonElement>;
  }[];
}
// the types for methods and variable available in your alert context
interface IAlertContext {
  alert: (args: IAlertNotification) => void;
  alertShown?: boolean;
  notification?: IAlertNotification;
  close: () => void;
}

// initialize default methods for context.
export const AlertContext = createContext<IAlertContext>({
  alert: () => {},
  close: () => {},
});

const AlertProvider: React.FC<{ children: React.ReactNode }> = ({
  children,
}) => {
  const [alertShown, setAlertShown] = useState(false); // toggles the view state of the alert component
  const [notification, setNotification] = useState<
    IAlertNotification | undefined
  >(); // stores the configuration data for the alert component
  const timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(); // stores the timer value for autoclosing the alert component

  // closes the alert component and reverts all config to default values.
  const close = () => {
    setAlertShown(false);
    setNotification(undefined);
    clearTimeout(timerRef.current);
  };

  // opens the alert component and configures its view state.
  const alert = (args: IAlertNotification) => {
    setNotification(args);
    setAlertShown(true);

    if (args.autoClose) {
      if (timerRef.current) {
        clearTimeout(timerRef.current);
      }

      timerRef.current = setTimeout(() => {
        close();
      }, notification?.delay || 3000);
    }

    return notification;
  };

  return (
    <AlertContext.Provider
      value={{
        notification,
        alert,
        alertShown,
        close,
      }}
    >
      {children}
    </AlertContext.Provider>
  );
};

export default AlertProvider;

实现警报组件UI。

现在您已经实现了该功能,下一步是创建组件UI并基于上下文中的配置设置视图状态。

复制以下代码并将其粘贴到src/components/Alert/Alert.tsx

import { useState } from "react";
import { useAlert } from ".";
import styles from "./styles.module.css";

const Alert = () => {
  const { notification, alertShown, close } = useAlert();
  const [textInputValue, setTextInputValue] = useState("");

  return (
    <div
      className={`
        ${styles.alert_container} ${alertShown ? styles.show : ''}`}
    >
      <div className={styles.alert}>
        <div className={styles.alert_content}>
          <p className={styles.alert_title}>{notification?.title || ""}</p>

          <div className={styles.alert_body}>
            <p>{notification?.message || ""}</p>
          </div>

          {notification?.inputProps && (
            <div className={styles.alert_textinput}>
              <input
                value={textInputValue}
                onChange={(e) => setTextInputValue(e.target.value)}
                {...notification?.inputProps}
              />
            </div>
          )}

          <div className={styles.alert_action}>
            {(notification?.actions || []).map((action) => (
              <div key={action.text} className={styles.btn}>
                <button
                  {...action.props}
                  onClick={() => {
                    action.callback?.(textInputValue);
                    setTextInputValue("");
                    close();
                  }}
                >
                  {action.text}
                </button>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
};

export default Alert;

接下来,您为组件设计。
src/component/Alert文件夹中创建一个名为styles.module.css的文件。

复制以下代码并将其粘贴到styles.module.css文件

.alert_container {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
  height: 100%;
  width: 100%;
  z-index: 999;
  transform: translateY(-100%);
  transition: all 500ms;
}
.alert_container.show {
  transform: translateY(0px);
}

.alert {
  width: 100%;
  max-width: 500px;
  margin: 0 auto;
  height: auto;
}

.alert_content {
  background-color: white;
  border-radius: 0px 0px 10px 10px;
  padding: 20px;
  width: 100%;
  box-shadow: 0px 10px 50px rgba(255, 255, 255, 0.3);
}

.alert_title {
  font-weight: 800;
  font-size: 1.275rem;
}

.alert_body {
  margin-top: 10px;
  font-size: 1rem;
}

.alert_textinput {
  margin-top: 20px;
  display: flex;
}

.alert_textinput input {
  width: 100%;
  height: 40px;
  border-radius: 8px;
  border: 1px solid grey;
  padding: 0px 10px;
}

.alert_action {
  display: flex;
  align-items: center;
  gap: 20px;
  margin-top: 20px;
}

.alert_action .btn {
  flex: 1;
}

.alert_action .btn button {
  height: 40px;
  background-color: #282c34;
  border: 0px;
  border-radius: 8px;
  width: 100%;
  font-weight: 600;
  color: white;
  cursor: pointer;
}

测试警报组件

现在您已经完成了组件,可以测试提示和通知用户的各种变体。

复制以下代码并将您的app.tsx文件替换为。

import logo from "./logo.svg";
import "./App.css";
import { useAlert } from "./components/Alert";

function App() {
  const { alert } = useAlert();

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <button
          onClick={() =>
            alert({
              title: "Notify",
              message: "Notification message",
              autoClose: true,
            })
          }
        >
          Notify
        </button>

        <button
          onClick={() =>
            alert({
              title: "Prompt without feedback",
              message: "Question to ask user before proceeding",
              actions: [
                {
                  text: "Cancel",
                },
                {
                  text: "Confirm",
                  callback: () => {
                    console.log('Confirmed')
                    // action to proceed
                  },
                },
              ],
            })
          }
        >
          Prompt without Feedback
        </button>
        <button
          onClick={() =>
            alert({
              title: "Prompt with feedback",
              message:
                "Question to ask user before proceeding. Expecting message from user",
              inputProps: { placeholder: "Enter feedback" },
              actions: [
                {
                  text: "Cancel",
                },
                {
                  text: "Confirm",
                  callback: (feedback) => {
                    console.log(feedback);
                    // action to proceed
                  },
                },
              ],
            })
          }
        >
          Prompt with Feedback
        </button>
      </header>
    </div>
  );
}

export default App;

结果!!!

React alert component notification only

React alert component prompt without feedback

React alert component prompt with feedback

结论。

yayyy,您已成功实现了React中的自定义警报组件。我知道这篇文章有点冗长,如果您有任何疑问,请务必将它们留在评论中,我会回答。
我也借此自由将代码推向Github。您可以访问[此处](https://github.com/haywhy43/create-custom-alert-component-with-react}