onChange 事件发生时意外调用 setState

问题描述 投票:0回答:1

StackOverflow 上的第一篇文章。很高兴认识你!

我正在尝试从 React 书中实现一个简单的整体应用程序,但我偶然发现了一个我无法解释的行为。我想请求您帮助理解为什么会发生这种情况。该示例是一个设计不佳的应用程序,稍后将其分解为可重用的组件。

当我在输入字段“标题”中键入任何字符时,onChangeTitle 事件将按预期调用。但在事件执行后,“articles”的 useState(位于 MyFeature() 函数定义的顶部)也会被调用,每次在“Title”中键入一个字符时,都会一次又一次有效地执行“id”函数。 “ 输入字段。

我已经调试了代码,似乎执行到了“MyFeature”的顶部,并向下移动了 setState 调用,但只有“文章”和“标题”的状态发生了变化。我期望整个 MyFeature 被重新渲染,但我没想到会调用“articles”setState 挂钩,因为它的值没有改变。知道为什么会发生这种情况吗?

谢谢您的帮助!

马可

import { useState, useCallback } from 'react';

const id = (function* () {
    let i = 1;
    while (true) {
    console.log(i);
    yield i;
    i += 1;
    }
  })();

function MyFeature() {
    const [articles, setArticles] = useState(
        [
            {
                id: id.next(),
                title: "Article 1",
                summary: "Article 1 summary",
                display: "none"
            },
            {
                id: id.next(),
                title: "Article 2",
                summary: "Article 2 summary",
                display: "none"
            }
        ]
    );
    const [title, setTitle] = useState("");
    const [summary, setSummary] = useState("");

    const onChangeTitle = useCallback((e) => {
        setTitle(e.target.value);
      }, []);

      const onChangeSummary = useCallback((e) => {
        setSummary(e.target.value);
      }, []);

      const onClickAdd = useCallback(() => {
        setArticles((state) => [
          ...state,
          {
            id: id.next(),
            title: title,
            summary: summary,
            display: "none",
          },
        ]);
        setTitle("");
        setSummary("");
      }, [summary, title]);

      const onClickRemove = useCallback((id) => {
        setArticles((state) => state.filter((article) => article.id !== id));
      }, []);
    
      const onClickToggle = useCallback((id) => {
        setArticles((state) => {
          const articles = [...state];
          const index = articles.findIndex((article) => article.id === id);
    
          articles[index] = {
            ...articles[index],
            display: articles[index].display ? "" : "none",
          };
    
          return articles;
        });
      }, []);

    return(
        <section>
            <header>
                <h1>Articles</h1>
                <input placeholder="Title" value={title} onChange={onChangeTitle} />
                <input placeholder="Summary" value={summary} onChange={onChangeSummary} />
                <button onClick={onClickAdd}>Add</button>
            </header>
            <article>
                <ul>
                    {articles.map((i) => (
                        <li key={i.id.value}>
                            <a href={'#${i.id}'} title="Toggle Summary" onClick={() => onClickToggle(i.id)}>{i.title}</a>
                            &nbsp;
                            <button href={'#${i.id}'} title="Remove" onClick={() => onClickRemove(i.id)}>&#10007;</button>
                            <p style={{ display: i.display }}>{i.summary}</p>
                        </li>
                    ))}
                </ul>
            </article>
        </section>
    );
}

export default MyFeature;
reactjs react-hooks
1个回答
0
投票

每次重新渲染时,函数的代码都会运行,因此由于函数的工作方式,

useState
初始化程序不可能不运行。然而,
useState
确实有一个变体,可以让您指定一个函数,而不是仅在第一次初始化状态时运行的
value

const [articles, setArticles] = useState(() => [
  {
    id: id.next(),
    title: "Article 1",
    summary: "Article 1 summary",
    display: "none"
  },
  {
    id: id.next(),
    title: "Article 2",
    summary: "Article 2 summary",
    display: "none"
  }
]);
© www.soinside.com 2019 - 2024. All rights reserved.