首页 > 解决方案 > 调用时 useState 不更新

问题描述

我正在建立一个餐厅网站模板。在项目中,我确实有一个带有两个箭头按钮的模式框来更改页面。pageNumber我通过 useState跟踪变量。不幸的是,该值永远不会更新,这会阻止页面更改。

这是 Menu.js 组件:

import { BrowserRouter as Router, Link } from 'react-router-dom';
import { useState } from 'react';

const Menu = () => {
    let [pageNumber, switchPage] = useState(1);
    
    let dish = {
        categories: [
            'proin blandit',
            'suspendisse non',
            'fermentum ultrices',
            'volutpat vulputat'
        ],

        names: [
            ['Sed fermentum', 'Sapien nec lobortis', 'Tristique in suspendisse', 'Pellentesque mattis elit', 'Vel interdum velit'],
            ['Nam nisi quam', 'Donec non viverra', 'Morbi suscipit mattis', 'Sed dignissim nisi', 'Aliquam vitae'],
            ['Curabitur ante mi', 'Nulla a felis', 'Donec porta convallis ', 'Vestibulum viverra ', 'Nullam viverra '],
            ['Vestibulum odio', 'Mauris neque ligula', 'Praesent iaculis nunc', 'Cras sollicitudin est', 'Class aptent taciti ']
        ],

        prices: [
            [13.99, 11.99, 15.99, 17.99, 21.99],
            [22.99, 20.99, 18.99, 16.99, 24.99],
            [11.99, 21.99, 31.99, 25.99, 15.99],
            [6.99, 8.99, 10.99, 4.99, 8.99]
        ]
    }

    let iterator = Math.abs(pageNumber % 4);
    
    let lineBreak = window.innerWidth <= 750 ? <br/> : undefined;

    return (
        <Router>
            <section className='menu'>
                <i className='fas fa-chevron-circle-left' id='menu-arrow-left' onClick={() => switchPage(pageNumber - 1)}></i>
                <h1 className='dish-category'>You are viewing {dish.categories[iterator]}</h1>
                <Link to='/home'><i className='fas fa-times'></i></Link>
                <ul className='dish-list'>
                    <li className='dish'>{dish.names[iterator][0]} {lineBreak} <span className='price'>{dish.prices[iterator][0]} PLN</span></li>
                    <li className='dish'>{dish.names[iterator][1]} {lineBreak} <span className='price'>{dish.prices[iterator][1]} PLN</span></li>
                    <li className='dish'>{dish.names[iterator][2]} {lineBreak} <span className='price'>{dish.prices[iterator][2]} PLN</span></li>
                    <li className='dish'>{dish.names[iterator][3]} {lineBreak} <span className='price'>{dish.prices[iterator][3]} PLN</span></li>
                    <li className='dish'>{dish.names[iterator][4]} {lineBreak} <span className='price'>{dish.prices[iterator][4]} PLN</span></li>
                </ul>
                <i className='fas fa-chevron-circle-right' id='menu-arrow-right' onClick={() => switchPage(pageNumber + 1)}></i>
            </section>
        </Router>
    )
}

export default Menu;

这就是我切换模式可见性的方式:

const hideModal = (e) => {
    e.preventDefault();

    let placeholder = document.getElementById('placeholder');
    placeholder.innerText = '';
    placeholder.style.display = 'none';

    let container = document.getElementById('container');
    container.style.filter = '';
    container.style.pointerEvents = 'auto';
}

const showModal = () => { 
    let placeholder = document.getElementById('placeholder');
    placeholder.innerHTML = ReactDOMServer.renderToString(<Menu />);
    placeholder.style.display = 'block';
    
    let container = document.getElementById('container');
    container.style.filter = 'blur(8px)';
    container.style.pointerEvents = 'none';
}

这是 App.js 中对应的 JSX 代码:

<div id='placeholder'><Menu /> <Contact /></div>

此外,我编写了一个检测点击位置的测试函数。当我在上面的示例中运行它时,我收到一条消息,我在模式框外单击,即使它是相反的。该函数从不同的文件运行。它看起来像这样:

let childrenNodes = [
    document.getElementsByClassName('menu')[0], 
    document.getElementsByClassName('dish-category')[0], 
    document.getElementsByClassName('dish-list')[0], 
    document.getElementsByClassName('dish')[0], 
    document.getElementsByClassName('dish')[1], 
    document.getElementsByClassName('dish')[2], 
    document.getElementsByClassName('dish')[3], 
    document.getElementsByClassName('dish')[4], 
    document.getElementsByClassName('price')[0], 
    document.getElementsByClassName('price')[1], 
    document.getElementsByClassName('price')[2], 
    document.getElementsByClassName('price')[3], 
    document.getElementsByClassName('price')[4]
];

const detectPlace = () => {
    window.addEventListener('click', (e) => {
        childrenNodes.some((node) => e.target === node) ? console.log('Clicked inside!') : console.log('Clicked outside!');
        console.log(e.target);
    });
}

你能告诉我为什么它会这样工作吗?

标签: javascriptreactjsjsxuse-state

解决方案


您正在渲染以下内容#placholder

let placeholder = document.getElementById('placeholder');
placeholder.innerHTML = ReactDOMServer.renderToString(<Menu />);

ReactDOMServer.renderToString(...)生成一个包含 HTML 的字符串。此字符串不包含任何 JavaScript,因此使结果非交互式。

渲染字符串()

ReactDOMServer.renderToString(element)

将 React 元素渲染为其初始 HTML。React 将返回一个 HTML 字符串。您可以使用此方法在服务器上生成 HTML,并在初始请求时发送标记以加快页面加载速度,并允许搜索引擎出于 SEO 目的抓取您的页面。

如果你调用ReactDOM.hydrate()一个已经有这个服务器渲染标记的节点,React 将保留它并且只附加事件处理程序,让你有一个非常高性能的首次加载体验。

如果你想要一个交互式 DOM 结构,你应该使用正常的ReactDOM.render(...)方法来渲染你的组件。

let placeholder = document.getElementById('placeholder');
ReactDOM.render(<Menu />, placeholder);

// import { BrowserRouter as Router, Link } from 'react-router-dom';
// import { useState } from 'react';
const { BrowserRouter: Router, Link } = ReactRouterDOM;
const { useState } = React;

const Menu = () => {
    let [pageNumber, switchPage] = useState(1);

    let dish = {
        categories: [
            'proin blandit',
            'suspendisse non',
            'fermentum ultrices',
            'volutpat vulputat'
        ],

        names: [
            ['Sed fermentum', 'Sapien nec lobortis', 'Tristique in suspendisse', 'Pellentesque mattis elit', 'Vel interdum velit'],
            ['Nam nisi quam', 'Donec non viverra', 'Morbi suscipit mattis', 'Sed dignissim nisi', 'Aliquam vitae'],
            ['Curabitur ante mi', 'Nulla a felis', 'Donec porta convallis ', 'Vestibulum viverra ', 'Nullam viverra '],
            ['Vestibulum odio', 'Mauris neque ligula', 'Praesent iaculis nunc', 'Cras sollicitudin est', 'Class aptent taciti ']
        ],

        prices: [
            [13.99, 11.99, 15.99, 17.99, 21.99],
            [22.99, 20.99, 18.99, 16.99, 24.99],
            [11.99, 21.99, 31.99, 25.99, 15.99],
            [6.99, 8.99, 10.99, 4.99, 8.99]
        ]
    }

    let iterator = Math.abs(pageNumber % 4);

    let lineBreak = window.innerWidth <= 750 ? <br/> : undefined;

    return (
        <Router>
            <section className='menu'>
                <i className='fas fa-chevron-circle-left' id='menu-arrow-left' onClick={() => switchPage(pageNumber - 1)}></i>
                <h1 className='dish-category'>You are viewing {dish.categories[iterator]}</h1>
                <Link to='/home'><i className='fas fa-times'></i></Link>
                <ul className='dish-list'>
                    <li className='dish'>{dish.names[iterator][0]} {lineBreak} <span className='price'>{dish.prices[iterator][0]} PLN</span></li>
                    <li className='dish'>{dish.names[iterator][1]} {lineBreak} <span className='price'>{dish.prices[iterator][1]} PLN</span></li>
                    <li className='dish'>{dish.names[iterator][2]} {lineBreak} <span className='price'>{dish.prices[iterator][2]} PLN</span></li>
                    <li className='dish'>{dish.names[iterator][3]} {lineBreak} <span className='price'>{dish.prices[iterator][3]} PLN</span></li>
                    <li className='dish'>{dish.names[iterator][4]} {lineBreak} <span className='price'>{dish.prices[iterator][4]} PLN</span></li>
                </ul>
                <i className='fas fa-chevron-circle-right' id='menu-arrow-right' onClick={() => switchPage(pageNumber + 1)}></i>
            </section>
        </Router>
    )
}

let placeholder = document.getElementById('placeholder');
ReactDOM.render(<Menu />, placeholder);
<div id="placeholder"></div>

<link crossorigin rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" />
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script crossorigin src="https://unpkg.com/react-router-dom@5/umd/react-router-dom.js"></script>


推荐阅读