首页 > 解决方案 > 使用钩子将状态从一个组件传递到另一个(不是子组件)

问题描述

我的搜索栏在一个Navbar组件中,该组件与所有屏幕都是一致的,所以它在我的App.js文件中。现在,我想存储用户在 Input (in Navbar.jsx) 中输入的字符串,将其带到App.js然后将其传递给我的其他组件。我不知道该怎么做。给出了我正在谈论的三个文件:

  1. App.js(包含Navbar和我的其他组件的文件)
  2. Navbar.jsx(包含我们从中获取字符串的输入搜索栏的文件)
  3. Homepage.jsx(我要访问搜索栏字符串以过滤我的结果的页面)

应用程序.js

import "./App.css";

import {
  Navbar,
  Homepage,
  Crypto,
  Exchanges,
  Settings,
} from "./components/index";
import { Layout } from "antd";
import Dock from "./components/Dock/Dock";
import { Switch, Route } from "react-router-dom";

function App() {
  return (
    <div className="App">
      <div className="navbar">
        <Navbar />
        <Dock />
      </div>
      <div className="main">
        <Layout>
          <div className="routes>">
            <Switch>
              <Route exact path="/">
                <Homepage />
              </Route>
              <Route exact path="/cryptocurrencies">
                <Crypto />
              </Route>
              <Route exact path="/exchanges">
                <Exchanges />
              </Route>
              <Route exact path="/settings">
                <Settings />
              </Route>
            </Switch>
          </div>
        </Layout>
      </div>
    </div>
  );
}

export default App;

主页.jsx

import React, { useState, useEffect } from "react";
import "./Homepage.css";
import CryptoCard from "../Card/Card";
import axios from "axios";

const Homepage = () => {
  const [coinData, setCoinData] = useState([], () => {
    const localData = localStorage.getItem("coinData");
    return localData ? JSON.parse(localData) : [];
  });

  useEffect(() => {
    const options = {
      method: "GET",
      url: "https://coinranking1.p.rapidapi.com/coins",
      headers: {
        "x-rapidapi-host": "coinranking1.p.rapidapi.com",
        "x-rapidapi-key": "API_KEY",
      },
    };

    axios
      .request(options)
      .then((response) => {
        setCoinData(response.data.data.coins);
        // persist in localStorage
        localStorage.setItem(
          "coinData",
          JSON.stringify(response.data.data.coins)
        );
      })
      .catch((error) => {
        console.error(error);
      });
  }, []);

  console.log("Coins names");
  coinData.forEach(function (coin) {
    console.log(coin.name);
  });

  return (
    <div className="homepage">
      <div className="heading">
        <h1>Discover</h1>
        <hr className="line" />
      </div>
      <div className="cards-container">
        {(coinData || []).map((coin) => (
          <CryptoCard
            name={coin.name}
            coinUrl={coin.websiteUrl}
            duration="4 minutes ago"
            symbol={coin.symbol}
            rank={coin.rank}
            exchanges={coin.numberOfExchanges}
            price={coin.price}
          />
        ))}
      </div>
    </div>
  );
};

export default Homepage;

导航栏.jsx

import React, { useState, useEffect } from "react";
import AppBar from "@mui/material/AppBar";
import Box from "@mui/material/Box";
import Toolbar from "@mui/material/Toolbar";
import IconButton from "@mui/material/IconButton";
import Badge from "@mui/material/Badge";
import MenuItem from "@mui/material/MenuItem";
import Menu from "@mui/material/Menu";
import AccountCircle from "@mui/icons-material/AccountCircle";
import NotificationsIcon from "@mui/icons-material/Notifications";
import MoreIcon from "@mui/icons-material/MoreVert";
import Icon from "../../images/logo.png";
import Brightness3Icon from "@mui/icons-material/Brightness3";
import WbSunnyTwoToneIcon from "@mui/icons-material/WbSunnyTwoTone";
import "./Navbar.css";
import HomeIcon from "@mui/icons-material/Home";

var notification = 1;

export default function PrimarySearchAppBar() {
  const [darkMode, setDarkMode] = useState(true);
  const darkModeToggle = () => {
    setDarkMode(!darkMode);
  };

  useEffect(() => {
    if (darkMode) {
      document.body.classList.add("dark");
    } else {
      document.body.classList.remove("dark");
    }
  }, [darkMode]);

  const [anchorEl, setAnchorEl] = React.useState(null);
  const [mobileMoreAnchorEl, setMobileMoreAnchorEl] = React.useState(null);

  const isMenuOpen = Boolean(anchorEl);
  const isMobileMenuOpen = Boolean(mobileMoreAnchorEl);

  const handleProfileMenuOpen = (event) => {
    setAnchorEl(event.currentTarget);
  };

  const handleMobileMenuClose = () => {
    setMobileMoreAnchorEl(null);
  };

  const handleMenuClose = () => {
    setAnchorEl(null);
    handleMobileMenuClose();
  };

  const handleMobileMenuOpen = (event) => {
    setMobileMoreAnchorEl(event.currentTarget);
  };

  const menuId = "primary-search-account-menu";
  const renderMenu = (
    <Menu
      anchorEl={anchorEl}
      anchorOrigin={{
        vertical: "top",
        horizontal: "right",
      }}
      id={menuId}
      keepMounted
      transformOrigin={{
        vertical: "top",
        horizontal: "right",
      }}
      open={isMenuOpen}
      onClose={handleMenuClose}
    >
      <MenuItem onClick={handleMenuClose}>Profile</MenuItem>
      <MenuItem onClick={handleMenuClose}>My account</MenuItem>
    </Menu>
  );

  const mobileMenuId = "primary-search-account-menu-mobile";
  const renderMobileMenu = (
    <Menu
      anchorEl={mobileMoreAnchorEl}
      anchorOrigin={{
        vertical: "top",
        horizontal: "right",
      }}
      id={mobileMenuId}
      keepMounted
      transformOrigin={{
        vertical: "top",
        horizontal: "right",
      }}
      open={isMobileMenuOpen}
      onClose={handleMobileMenuClose}
    >
      <MenuItem>
        <IconButton size="large" color="inherit" style={{ marginTop: "3px" }}>
          {"day" === "night" ? (
            <Brightness3Icon style={{ color: "#000000" }} />
          ) : (
            <WbSunnyTwoToneIcon style={{ color: "#000000" }} />
          )}
        </IconButton>
        {"day" === "night" ? <p>Dark Mode</p> : <p> Light Mode</p>}
      </MenuItem>
      <MenuItem>
        <IconButton
          size="large"
          aria-label="show 17 new notifications"
          color="inherit"
        >
          <Badge badgeContent={notification} color="error">
            <NotificationsIcon />
          </Badge>
        </IconButton>
        <p>Notifications</p>
      </MenuItem>
      <MenuItem onClick={handleProfileMenuOpen}>
        <IconButton
          size="large"
          aria-label="account of current user"
          aria-controls="primary-search-account-menu"
          aria-haspopup="true"
          color="inherit"
        >
          <AccountCircle />
        </IconButton>
        <p>Profile</p>
      </MenuItem>
      <MenuItem>
        <IconButton size="large" aria-haspopup="true" color="inherit">
          <HomeIcon />
        </IconButton>
        <p>Home</p>
      </MenuItem>
    </Menu>
  );

  //RENDERING ON SCREEN
  return (
    <div className="navbar-container">
      <Box sx={{ flexGrow: 1 }}>
        <AppBar
          position="static"
          style={{ background: "#171721" }}
          elevation={0}
        >
          <Toolbar>
            <img src={Icon} alt="alt" className="app-logo" />
            <Box sx={{ flexGrow: 1 }} />
            <div className="search">
              <input
                type="text"
                placeholder="Find your Exchange or Currency..."
                className="search-bar"
              />
            </div>
            <Box sx={{ flexGrow: 1 }} />
            <Box sx={{ display: { xs: "none", md: "flex" } }}>
              <IconButton size="large" color="inherit">
                {darkMode === true ? (
                  <a className="mode" onClick={darkModeToggle}>
                    <WbSunnyTwoToneIcon style={{ color: "#B7B7BA" }} />
                  </a>
                ) : (
                  <a className="mode" onClick={darkModeToggle}>
                    <Brightness3Icon style={{ color: "#B7B7BA" }} />
                  </a>
                )}
              </IconButton>
              <IconButton
                size="large"
                aria-label="show 17 new notifications"
                color="inherit"
                style={{ color: "#B7B7BA" }}
              >
                <Badge badgeContent={notification} color="error">
                  <NotificationsIcon />
                </Badge>
              </IconButton>
              <IconButton
                size="large"
                edge="end"
                aria-label="account of current user"
                aria-controls={menuId}
                aria-haspopup="true"
                onClick={handleProfileMenuOpen}
                color="inherit"
                style={{ color: "#B7B7BA" }}
              >
                <AccountCircle />
              </IconButton>
            </Box>
            <Box sx={{ display: { xs: "flex", md: "none" } }}>
              <IconButton
                size="large"
                aria-label="show more"
                aria-controls={mobileMenuId}
                aria-haspopup="true"
                onClick={handleMobileMenuOpen}
                color="inherit"
              >
                <MoreIcon />
              </IconButton>
            </Box>
          </Toolbar>
        </AppBar>
        {renderMobileMenu}
        {renderMenu}
      </Box>
    </div>
  );
}

如何将状态从Navbarto传递App到 my Homepage

不是问题的一部分,但如果您对如何从map主页中的功能过滤结果有任何见解,请告诉我。将不胜感激!

标签: reactjsreact-hooksstate

解决方案


您可以简单地在 App.js 中声明该状态并将其用作组件 Navbar 和 Homepage 中的道具

应用程序.js

import "./App.css";

import {
  Navbar,
  Homepage,
  Crypto,
  Exchanges,
  Settings,
} from "./components/index";
import { Layout } from "antd";
import Dock from "./components/Dock/Dock";
import { Switch, Route } from "react-router-dom";

function App() {
const [searchValue, setSearchValue] = useState("");

  return (
    <div className="App">
      <div className="navbar">
        <Navbar  searchValue={searchValue} setSearchValue={setSearchValue}/>
        <Dock />
      </div>
      <div className="main">
        <Layout>
          <div className="routes>">
            <Switch>
              <Route exact path="/">
                <Homepage setSearchValue={setSearchValue} searchValue={searchValue}/>
              ...          
  );
}

export default App;

主页.jsx

const Homepage = ({setSearchValue, searchValue}) => {
...

导航栏.jsx

const Navbar= ({setSearchValue, searchValue}) => {
...

如果你有更多的组件要处理甚至是孙子,使用 props 可能是多余的,所以我建议你学习 redux 或 useContext 钩子来管理你的状态


推荐阅读