在 Reactstrap 中,如何自定义子组件的警报消息和可见状态?

In reactstrap, how do I customize the alert message and visible state from a child component?

我正在使用 React 16.13.0 并尝试使用 reactstrap Alert 组件在提交某些表单时显示消息。我已将 Alert 组件放置在我的 App 模板中我想要的位置 ...

import { Alert } from 'reactstrap';

function App() {
  return (
    <Router>
      <div className="App">
        <nav className="navbar navbar-expand-lg navbar-light fixed-top">
          <div className="container">
            <Link className="navbar-brand" to={"/add"}>
              Chicommons
            </Link>
            <NavBar />
          </div>
        </nav>

        <div className="auth-wrapper">
          <div className="auth-inner">
            <Alert color="info" isOpen={this.state.visible} >
              I am an alert and I will disappear in 2sec.!
            </Alert>
            <Switch>
              <Route exact path="/" component={Add} />
              <Route path="/add" component={Add} />
              <Route path="/edit/:id" component={Edit} />
              <Route path="/search" component={Search} />
              <Route path="/:coop_id/people" component={AddPerson} />
              <Route path="/:coop_id/listpeople" component={ListPeople} />
            </Switch>
          </div>
        </div>
      </div>
    </Router>
  );
}

export default App;

我在一些事情上遇到了问题。我的表单组件之一 src/containers/FormContainer.jsx 具有此提交处理程序 ...

  const handleFormSubmit = (e) => {
    e.preventDefault();
    // Make a copy of the object in order to remove unneeded properties
    const NC = JSON.parse(JSON.stringify(coop));
    delete NC.addresses[0].country;

    const url = coop.id ? REACT_APP_PROXY + "/coops/" + coop.id : REACT_APP_PROXY + "/coops/";
    const method = coop.id ? "PATCH" : "POST";
    fetch(url, {
      method: method,
      body: JSON.stringify(NC),
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
      },
    })
      .then((response) => {
        if (response.ok) {
          return response.json();
        } else {
          throw response;
        }
      })
      .then((data) => {
        const result = data;
        history.push({
          pathname: "/" + result.id + "/people",
          state: { coop: result },
        });
        window.scrollTo(0, 0);

        /** Would like to place alert here **/

      })
      .catch((err) => {
        console.log(err);
        err.text().then((errorMessage) => {
          setErrors(JSON.parse(errorMessage));
        });
      });
  };

我想使用在上述处理程序中生成的自定义消息启用 reactstrap 警报。但是,我不知道如何控制父组件的状态。我假设我必须在父组件中创建一些消息状态并控制我已经拥有的可见状态,但不确定如何从子组件中做到这一点。

就在 function App() { 下面。添加:

const [alertMessage, setAlertMessage] = React.useState("")

并将您的警报更改为:

<Alert color="info" isOpen={alertMessage!=""} toggle={()=>setAlertMessage("")} >
    {alertMessage}
</Alert>

然后我不知道你的应用程序的其余部分是如何布局的,但你想将 setAlertMessage 函数作为回调传递给 handleFormSubmit,并调用它 in/nearsetErrors

您可以创建一个上下文,以便在应用程序的任何位置轻松访问警报。

AlertProvider.js

import React, { useState, useCallback, useContext, createContext } from 'react'

const AlertContext = createContext()

export function AlertProvider(props) {
  const [open, setOpen] = useState(false)
  const [message, setMessage] = useState()


  const handleClose = useCallback(() => {
    setOpen(false)
  }, [setOpen])

  const handleOpen = useCallback(message => {
    setMessage(message)
    setOpen(true)
  }, [setMessage, setOpen])
    
  return (
    <AlertContext.Provider value={[handleOpen, handleClose]}>
      {props.children}
      <Alert color="info" isOpen={open} toggle={handleClose} >
        {message}
      </Alert>
    </AlertContext.Provider>
  )
}


export function useAlert() {
  const context = useContext(AlertContext);
  if (!context)
    throw new Error('`useAlert()` must be called inside an `AlertProvider` child.')

  return context
}

更新您的 App.js

import { Alert } from 'reactstrap';
import { AlertProvider } from './AlertProvider';

function App() {
  return (
    <AlertProvider>
      <Router>
        <div className="App">
          <nav className="navbar navbar-expand-lg navbar-light fixed-top">
            <div className="container">
              <Link className="navbar-brand" to={"/add"}>
                Chicommons
              </Link>
              <NavBar />
            </div>
          </nav>

          <div className="auth-wrapper">
            <div className="auth-inner">
              <Switch>
                <Route exact path="/" component={Add} />
                <Route path="/add" component={Add} />
                <Route path="/edit/:id" component={Edit} />
                <Route path="/search" component={Search} />
                <Route path="/:coop_id/people" component={AddPerson} />
                <Route path="/:coop_id/listpeople" component={ListPeople} />
              </Switch>
            </div>
          </div>
        </div>
      </Router>
    </AlertProvider>
  );
}

export default App;

然后您可以在功能组件中使用它:

import React, { useEffect } from 'react'
import { useAlert } from './AlertProvider'

function MyComponent() {
  const [open, close] = useAlert();

  useEffect(() => {
    // when some condition is met
      open("Hi") // closable with the toggle, or in code via close()
  })
}

这使用祈使语气通过调用open()close()打开和关闭。如果你想要一种声明式的情绪,上下文应该直接 return setMessagesetOpen 函数。

您也可以尝试将警报组件放在其他地方。