简体   繁体   English

根据子组件参数之一反应设置初始 state

[英]React setting initial state based on one of child components parameters

I am making an app with menu bar and sliding selected menu item indicator.我正在制作一个带有菜单栏和滑动选定菜单项指示器的应用程序。 It kind of works, but I have several problems:它有点工作,但我有几个问题:

  1. The initial state ( widthOffset , leftOffset and color ) is hardcoded, but I need it to always follow the active NavLink , so when I open my app - the indicator is immediately in the right place at selected NavLink (if you select anything but Home NavLink and reload app, you will be at last page, but indicator resets to hardcoded state).最初的 state ( widthOffsetleftOffsetcolor )是硬编码的,但我需要它始终遵循活动的NavLink ,所以当我打开我的应用程序时 - 指示器立即在所选NavLink的正确位置(如果你 select 除了Home NavLink并重新加载应用程序,您将在最后一页,但指示器重置为硬编码状态)。
  2. I did not find a way to get value of activeStyle from e.target , so colors are also weirdly hardcoded with this double menuItems.*NavLink name*.color in each NavLink .我没有找到从e.target获取activeStyle值的方法,因此 colors 在每个NavLink中也用这个双menuItems.*NavLink name*.color进行了奇怪的硬编码。

What is the best way to implement this?实现这一点的最佳方法是什么?

full codesandbox: https://codesandbox.io/s/ecstatic-moon-mqbnk完整的代码框: https://codesandbox.io/s/ecstatic-moon-mqbnk

code:代码:

import React, { useState } from "react";
import { NavLink } from "react-router-dom";

const Navigation = () => {
  const menuItems = {
    Home: {
      color: 'orange',
    },
    About: {
      color: 'green',
    },
    Contacts: {
      color: 'rebeccapurple',
    },
  }

  const [offsetWidth, setWidth] = useState(84);
  const [offsetLeft, setLeft] = useState(26);
  const [color, setColor] = useState("orange");

  function switchMenu(e, color) {
    setWidth(e.target.offsetWidth);
    setLeft(e.target.offsetLeft);
    setColor(color);
  }

  return (
    <nav className="nav">
      <NavLink
        refs="Home"
        exact
        className="nav-item"
        activeClassName="nav-item is active"
        activeStyle={{ color: menuItems.Home.color }}
        to="/"
        onClick={(e) => switchMenu(e, menuItems.Home.color)}
      >
        Home
      </NavLink>
      <NavLink
        refs="About"
        exact
        className="nav-item"
        activeClassName="nav-item is active"
        activeStyle={{ color: menuItems.About.color }}
        to="/about"
        onClick={(e) => switchMenu(e, menuItems.About.color)}
      >
        About
      </NavLink>
      <NavLink
        refs="Contacts"
        exact
        className="nav-item"
        activeClassName="nav-item is active"
        activeStyle={{ color: menuItems.Contacts.color }}
        to="/contact"
        onClick={(e) => switchMenu(e, menuItems.Contacts.color)}
      >
        Contacts
      </NavLink>
      <span
        style={{
          position: "absolute",
          left: `${offsetLeft}px`,
          width: `${offsetWidth}px`,
          backgroundColor: `${color}`,
          bottom: "0px",
          height: "5px",
          transition: ".4s",
          zIndex: "1",
          borderRadius: "8px 8px 0 0",
        }}
      ></span>
    </nav>
  );
};

export default Navigation;

UPD:升级版:

I managed o solve some problems, using isActive of NavLink , now the indicator is always in place, but still have a lil bit of trouble:我设法解决了一些问题,使用NavLinkisActive ,现在指示器总是在适当的位置,但仍然有点麻烦:

  1. I am using onClick and this destroys the state and rerendering power of React.我正在使用onClick ,这会破坏 state 和 React 的重新渲染能力。 I did not find a way to toggle useEffect to rerender the indicator when I change selected link.当我更改选定的链接时,我没有找到一种方法来切换useEffect以重新呈现指示器。 Also when I try not to directly change the state onClick , but to run setCurrentPage() it works 1/2 times, cause onClick happens fatser, than className change.此外,当我尝试不直接更改 state onClick ,但运行setCurrentPage()它工作 1/2 次,导致onClick发生更胖,而不是类。
  2. If you press Ctrl + F5 and the fonts, etc. jump - the indicator renders a little bit not in it's place.如果您按下Ctrl + F5并且 fonts 等会跳转 - 指示器会呈现一点点不在它的位置。 Would be nice if I could render it after all is settled.如果我能在一切都解决后渲染它会很好。

updated codesandbox: https://codesandbox.io/s/strange-shadow-5jo68更新的代码框: https://codesandbox.io/s/strange-shadow-5jo68

updated Navigattion.js code:更新了 Navigattion.js 代码:

import React, { useState, useRef, useEffect } from "react";
import { NavLink } from "react-router-dom";

const Navigation = () => {
  const [offsetWidth, setWidth] = useState(null);
  const [offsetLeft, setLeft] = useState(null);
  const [color, setColor] = useState(null);

  const Home = useRef(null);
  const About = useRef(null);
  const Contacts = useRef(null);

  const menuItems = {
    Home: {
      ref: Home,
      color: "orange",
    },
    About: {
      ref: About,
      color: "green",
    },
    Contacts: {
      ref: Contacts,
      color: "rebeccapurple",
    },
  };

  function changeIndicator(e, color) {
    setWidth(e.offsetWidth);
    setLeft(e.offsetLeft);
    setColor(color);
  }

  function setCurrentPage() {
    Object.keys(menuItems).forEach((key) => {
      if (
        menuItems[key].ref.current.className === "nav-item nav-item is active"
      ) {
        changeIndicator(menuItems[key].ref.current, menuItems[key].color);
      }
    });
  }

  useEffect(setCurrentPage);

  return (
    <nav className="nav">
      <NavLink
        ref={Home}
        isActive={(match) => {
          if (!match) {
            return false;
          }
          return true;
        }}
        exact
        className="nav-item"
        activeClassName="nav-item is active"
        activeStyle={{ color: menuItems.Home.color }}
        to="/"
        onClick={(e) => changeIndicator(e.target, menuItems.Home.color)}
      >
        Home
      </NavLink>
      ...

As I said in my comment you can use references to check what is the active link and then set the state正如我在评论中所说,您可以使用参考来检查活动链接是什么,然后设置 state

  1. Change your class name to is-active将您的 class 名称更改为is-active
  className="nav-item"
  activeClassName="is-active"
  1. Add references to the links and get the active one (this code can be better)添加对链接的引用并获取活动链接(此代码可以更好)
  const homeLink = useRef(null);
  const aboutLink = useRef(null);
  const contactLink = useRef(null);

  useEffect(() => {
    if (homeLink.current.className.includes("is-active")) {
      setWidth(homeLink.current.offsetWidth);
      setLeft(homeLink.current.offsetLeft);
      setColor(menuItems.Home.color);
    } else if (aboutLink.current.className.includes("is-active")) {
      setWidth(aboutLink.current.offsetWidth);
      setLeft(aboutLink.current.offsetLeft);
      setColor(menuItems.About.color);
    } else if (contactLink.current.className.includes("is-active")) {
      setWidth(contactLink.current.offsetWidth);
      setLeft(contactLink.current.offsetLeft);
      setColor(menuItems.Contacts.color);
    }
  }, []);


  ....

  <NavLink
     ref={homeLink}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM