【问题标题】:How to force a route in React如何在 React 中强制路由
【发布时间】:2021-12-25 23:48:21
【问题描述】:

在我关闭模态框后,我正在尝试按照这个 SO Answer“回家”...

import React, { Suspense, useState } from 'react';
import { BrowserRouter, Route, Switch, useHistory } from "react-router-dom";
import './App.css';
import { Button } from 'reactstrap';
import Slideshow from './components/Slideshow.js';
import LogoHeader from './components/LogoHeader';
import Login from "./components/Login/Login.js";
import ChangePassword from "./components/Login/ChangePassword.js";
import useToken from "./components/useToken";
import NewFooter from "./components/NewFooter";
import GetCategories from "./components/GetCategories";
import { formatter } from './components/common.js'
import { GetCart, Increment, Decrement } from './components/ShoppingCart/CartHandler.js'
import CheckoutModal from './components/ShoppingCart/CheckoutModal.js'

const FeaturedCards = React.lazy(() => import('./components/featuredCards'));
const ProdCard = React.lazy(() => import('./components/productCards'));
const Portal = React.lazy(() => import('./components/Portal/portal'));

function App() {    
    const { token, setToken } = useToken();
    const [cart, setCart] = useState(GetCart());
    const [isOpen, setIsOpen] = useState(false);
    const history = useHistory();

    if (!token) {
        return <Login setToken={setToken} />
    }
    
    if (token.forcePasswordChange === true) {
        return <ChangePassword setToken={setToken} />
    }

    function handleIncrementClick(item) {
        Increment(item.ItemNumber, cart);
        setCart(GetCart);
    }

    function handleDecrementClick(item) {
        Decrement(item.ItemNumber, cart);
        setCart(GetCart);
    }

    let onRequestClose = () => {
        setIsOpen(false);
        setCart(GetCart);
        history.push('/')
    }

    let handleClick = () => {
        setIsOpen(true)        
    }

    return (
        <div className="App">
            <BrowserRouter>
                <p className="greeting">Hello, {token.firstName}</p>
                <LogoHeader />
                <GetCategories />                
                <Switch>
                    <Route path="/cart">
                        <Suspense fallback={<div>Loading...</div>}>
                            <div>
                                <table className="table table-striped table-bordered">
                                    <thead>
                                        <tr>
                                            <th className="number">Item Number</th>
                                            <th className="price">Price</th>
                                            <th className="quantity">Quantity</th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        {cart.map(item =>
                                            <tr key={item.ItemNumber}>
                                                <td>{item.ItemNumber}</td>
                                                <td>{formatter.format(item.Price)}</td>
                                                <td>{item.Quantity}</td>
                                                <td><Button className="BtnIncrement" onClick={() => handleIncrementClick(item)}>{'+'}</Button></td>
                                                <td><Button className="BtnDecrement" onClick={() => handleDecrementClick(item)}>{'-'}</Button></td>
                                            </tr>
                                        )}
                                    </tbody>
                                </table>
                                <Button onClick={() => handleClick()}>Checkout</Button>
                                {isOpen ? <CheckoutModal onRequestClose={onRequestClose} /> : null}
                            </div>
                        </Suspense>
                    </Route>
                    <Route path="/portal">
                        <Suspense fallback={<div>Loading...</div>}>
                            <Portal />
                        </Suspense>
                    </Route>
                    <Route path="/">
                        <Slideshow id="slideshow" />
                        <div id="productContainer">
                            <br />
                            <h3>Featured Products</h3>
                            <br />
                            <Suspense fallback={<div>Loading...</div>}>
                                
                                <FeaturedCards setCartFunc={setCart} />
                                
                            </Suspense>
                            <br />
                            <h3>Most Popular</h3>
                            <br />
                            <Suspense fallback={<div>Loading...</div>}>
                                <ProdCard />
                            </Suspense>
                            <br />
                            <h3>New Products</h3>
                            <br />
                            <Suspense fallback={<div>Loading...</div>}>
                                <ProdCard />
                            </Suspense>
                        </div>
                    </Route>                               
                </Switch>
                <NewFooter />
            </BrowserRouter>
        </div>
    );
}
export default App;

更新

根据要求,我的CheckoutModal

import React from 'react';
import "./Checkout.scss"
import AddressBlock from './AddressBlock';
import PaymentBlock from './PaymentBlock';
import ShippingBlock from './ShippingBlock';
import TotalsBlock from './TotalsBlock';
import { Modal, ModalHeader, ModalBody } from 'reactstrap';

class CheckoutModal extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            name: 'React',
            shippingMethod: null
        };
    }    

    setShippingMethod(method) {
        this.setState(state => ({ ...state, shippingMethod: method }));
    }

    render() {
        const buttonStyles = {
            position: "absolute",
            top: "-35px",
            right: "10px",
            border: "0",
            background: "none"
        };        

        return (
            <Modal id="checkout"
                isOpen
                size='xl'>
                <button onClick={this.props.onRequestClose} style={buttonStyles}>x</button>
                <ModalHeader className="header">
                    Checkout                    
                </ModalHeader>
                <ModalBody>                    
                    <div className="row">
                        <AddressBlock />
                        <ShippingBlock setShippingMethod={this.setShippingMethod.bind(this)} shippingMethod={this.state.shippingMethod}/>
                    </div>
                    <div className="row">
                        <PaymentBlock onRequestClose={this.props.onRequestClose} />
                        <TotalsBlock />
                    </div>
                </ModalBody>
            </Modal>
        );
    }
}
export default CheckoutModal;

我从我的函数onRequestClose 得到history is undefined。我尝试在前面加上this,但这没有用。这是因为App.js 不是一个类组件或者仅仅是一个函数?任何提示或建议将不胜感激。

nodejs 16.13.0

react-router-dom 8.1.2

【问题讨论】:

  • let 更改为constconst onRequestClose 将起作用
  • @AshishKamble 我刚刚尝试过,但仍然出现同样的错误。
  • 是的,您使用props 访问,所以未定义,不要那样做
  • 也输入你的CheckoutModal 代码
  • @AshishKamble 我发布了我的模态代码

标签: javascript reactjs react-router-dom


【解决方案1】:

在 App.js 中使用 useRouter 将不起作用。 Becourse它在浏览器路由器之外。 BrowserRouter 包装的组件只能使用 useRouter。希望这会有所帮助。

【讨论】:

  • 他没有使用useRouter,是吗?
【解决方案2】:

问题

您正在使用/调用来自AppuseHistory 挂钩,但App 是渲染BrowserRouter 的组件,它为应用程序提供路由上下文,包括有效的history 对象引用。

解决方案

BrowserRouter 移出App,很可能移到您正在渲染Appindex.js。这是为了为AppApp 的子树中的所有其他组件提供有效的路由上下文以供访问。

示例 index.js

...
import { BrowserRouter } from "react-router-dom";
...

const rootElement = document.getElementById("root");
ReactDOM.render(
  <StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </StrictMode>,
  rootElement
);

应用程序

function App() {    
  const { token, setToken } = useToken();
  const [cart, setCart] = useState(GetCart());
  const [isOpen, setIsOpen] = useState(false);
  const history = useHistory(); // <-- will now be defined

  ...

  const onRequestClose = () => {
    setIsOpen(false);
    setCart(GetCart);
    history.push('/'); // <-- should navigate now
  }

  ...

  return (
    <div className="App">
      <p className="greeting">Hello, {token.firstName}</p>
      <LogoHeader />
      <GetCategories />                
      <Switch>
        <Route path="/cart">
          <Suspense fallback={<div>Loading...</div>}>
            <>
              <table className="table table-striped table-bordered">
                ...
              </table>
              <Button onClick={handleClick}>Checkout</Button>
              {isOpen && <CheckoutModal onRequestClose={onRequestClose} />}
            </>
          </Suspense>
        </Route>
        ...                               
      </Switch>
      <NewFooter />
    </div>
  );
}

【讨论】:

    猜你喜欢
    • 2017-05-12
    • 1970-01-01
    • 2017-09-19
    • 1970-01-01
    • 2013-03-17
    • 2016-02-24
    • 2016-07-21
    • 2012-10-18
    • 1970-01-01
    相关资源
    最近更新 更多