【问题标题】:React.js component not re-rendering children when the useState hook changes state当 useState 钩子更改状态时,React.js 组件不会重新渲染子组件
【发布时间】:2021-03-05 10:13:32
【问题描述】:

我有一个父组件NavBar,它有两个子组件:NavItemsIcon。当其中任何一个孩子被点击时,他们的外观都应该改变。一个非常标准的功能。

另外我想要的是能够根据屏幕宽度设置初始状态。为此,我创建了一个自定义挂钩,我称之为useMatchMedia。每次调用 useMatchMedia 时,我都需要覆盖该状态,无论它当前具有什么状态以及使用这个新状态重新渲染子组件。

我相信问题出在 return 语句之前的 NavBar 内。但以防万一,我也提供了自定义挂钩的代码。

(滚动到我的代码下方,查看我解决问题的尝试)。

这是父级:

function NavBar() {
    const matchMedia = useMatchMedia(false, "tablet"); // returns true or false if the screen width is that of a tablet or not
    const [hideNavItems, setHideNavItems] = useState(matchMedia);

    let onHandleHideNavItems = () => {
        setHideNavItems(!hideNavItems);
    };

    return (
        <Nav>
            <NavItems
                hideNavItems={hideNavItems}
                onHandleHideNavItems={onHandleHideNavItems} // onClick={() => onHandleHideNavItems(!hideNavItems)}
            />
            <Icon
                hideNavItems={hideNavItems}
                onHandleHideNavItems={onHandleHideNavItems} // onClick={() => onHandleHideNavItems(!hideNavItems)}
            />
        </Nav>
    );
}

export default NavBar;

这是我的自定义钩子:

function useMatchMedia(initialState, device) {
    const [passQuery, setPassQuery] = useState(initialState);
    const matchMediaRef = useRef(null);

    let widthType = null;
    let chosenDevice = device;

    switch (chosenDevice) {
        case "phone":
            chosenDevice = 425;
            widthType = "max";
            break;
        case "tablet":
            chosenDevice = 768;
            widthType = "max";
            break;
        case "smallLaptop":
            chosenDevice = 1024;
            widthType = "max";
            break;
        case "largeLaptop":
            chosenDevice = 1440;
            widthType = "max";
            break;
        default:
            chosenDevice = 1800;
            widthType = "min";
    }

    useEffect(() => {
        matchMediaRef.current = window.matchMedia(
            `(${widthType}-width: ${chosenDevice}px)`
        );
        const initialMatch = matchMediaRef.current.matches;

        if (initialMatch) {
            setPassQuery(true);
        } else {
            setPassQuery(false);
        }

        const target = (event) => {
            if (event.matches) {
                setPassQuery(true);
            } else {
                setPassQuery(false);
            }
        };

        matchMediaRef.current.addListener(target);

        return () => {
            matchMediaRef.current.removeListener(target);
        };
    }, [widthType, chosenDevice]);

    return passQuery;
}

export default useMatchMedia;

我曾尝试在我的 NavBar 组件中使用useEffect,例如:

 useEffect(() => {
        setHideNavItems(!hideNavItems);
     }, [matchMedia, hideNavItems]);

这样,每当 matchMedia 发生变化时,我都应该重新渲染,因为 hideNavItems 的初始状态设置为 matchMedia,这应该会更新我的状态,从而更新孩子。这失败了,因为它创建了一个无限循环。我理解为什么会有一个无限循环,但我也相信解决方案接近于这样。

我也尝试在onHandleHideNavItems 上使用useCallback,但这不起作用。

我尝试使用useRef 将渲染限制为更新而不是初始渲染。这也不起作用。

我有点迷茫。非常感谢任何帮助。

【问题讨论】:

  • 抱歉,我对您要完成的工作有点困惑,请查看此sandbox 这是您需要的吗?
  • 我不敢相信我离我有多近却忽略了这一点。如果您发布您的“useEffect”,我会将其标记为已接受的答案。谢谢。
  • 是的,确实非常接近。我很高兴我的云帮助。谢谢。
  • 我发现你的回答有问题。我需要状态被“UseMatchMedia”覆盖。如果屏幕尺寸变大时“hideNavItems”已经为假,这意味着“UseMatchMedia”也将返回假。 “NavItems”组件不会重新渲染。有任何想法吗?每次调用“useMatchMedia”时,我都需要“NavItems”重新渲染。

标签: reactjs react-hooks


【解决方案1】:

只要屏幕宽度根据您的useMatchMedia 挂钩逻辑发生变化,只需使用useEffecthideNavItems 状态重置回matchMedia 值:

useEffect(() => {
    setHideNavItems(matchMedia);
}, [matchMedia]);

【讨论】:

  • 我发现你的回答有问题。我需要状态被“UseMatchMedia”覆盖。如果屏幕尺寸变大时“hideNavItems”已经为假,这意味着“UseMatchMedia”也将返回假。 “NavItems”组件不会重新渲染。有任何想法吗?每次调用“useMatchMedia”时,我都需要“NavItems”重新渲染。
  • 基于当前的UseMatchMedia钩子逻辑,钩子只检查平板(第二个参数),所以它只会在屏幕点击768 px时调用。我猜你可能需要this
  • 问题在于它不断发射。我的 useMatchMedia 挂钩仅在屏幕宽度超过指定值时触发。我不应该更改 useMatchMedia 挂钩。我只需要两个子组件来识别更改。解决方案很可能在于创建一个具有相同返回值的新对象,或者可能向接受 props 的子组件添加状态挂钩。我仍在到处寻找解决方案。
猜你喜欢
  • 2020-10-29
  • 1970-01-01
  • 2020-01-26
  • 1970-01-01
  • 2020-10-11
  • 2018-06-04
  • 2017-10-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多