【问题标题】:useState doesn't update when called调用时 useState 不更新
【发布时间】:2021-11-15 04:27:45
【问题描述】:

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

这里是 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);
    });
}

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

【问题讨论】:

  • 尝试switchPage((prevState) =&gt; prevState - 1) 而不是switchPage(pageNumber - 1)
  • @VitaliyRayets,它仍然不适合我,没有任何改变
  • 变量iterator 无反应
  • @VitaliyRayets,它依赖于 pageNumber 变量,它不会自行改变
  • 只是想知道,您能否将带有 onClick 的 i 元素包装到 div(或 a)中并将处理程序设置为新的 div?

标签: javascript reactjs jsx use-state


【解决方案1】:

您正在渲染#placholder 的内容:

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

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

renderToString()

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>

【讨论】:

    猜你喜欢
    • 2021-01-17
    • 2023-01-18
    • 2021-06-08
    • 2021-01-25
    • 2021-10-20
    • 2020-03-06
    • 1970-01-01
    • 2020-12-22
    • 2022-01-15
    相关资源
    最近更新 更多