如何在不改变组件行为的情况下摆脱 useEffect?

huangapple go评论62阅读模式
英文:

How to get rid of useEffect without changing the component's behavior?

问题

有一种趋势认为在React v18中应尽量减少使用useEffect

React文档说:

Effect允许您将组件与某些外部系统(例如聊天服务)同步。外部系统指的是任何不受React控制的代码。

然而,有许多情况下,我无法找到一种方法来移除useEffect,而不影响组件的预期行为或使其看起来非常丑陋。

例如,下面的情况:

import { useEffect, useState } from "react";

interface SearchBarProps {
  programType: "movies" | "series";
}

export function SearchBar({ programType }: SearchBarProps): JSX.Element {
  const [searchTerm, setSearchTerm] = useState<string>("");
  const [selectedYear, setSelectedYear] = useState<number | null>();
  const [counter, setCounter] = useState<number>(0);

  /* 
  当programType prop更改时重新设置searchTerm和selectedYear
  */
  useEffect(() => {
    searchTerm !== "" && setSearchTerm("");
    typeof selectedYear === "number" && setSelectedYear(null);
  }, [programType]);

  const increase = () => {
    setCounter(counter => counter + 1);
  };

  return (
    <div className="search-bar">
      <p>{searchTerm}</p>
      <p>{selectedYear}</p>
      <span className="counter__output">{counter}</span>
      <div className="btn__container">
        <button onClick={increase}>+</button>
      </div>
    </div>
  );
}

有没有一种方法可以移除useEffect而不影响组件的行为?

英文:

There is a trend saying that devs should get rid of useEffect as much as possible in React v18.

React documentation says

> An Effect lets you keep your component synchronized with some external
> system (like a chat service). External system means any piece of
> code that’s not controlled by React

However there are many situation where I can't find a way to remove the useEffect without making my component stop working as expected or look extremely ugly.

I.e. the case below:

import { useEffect, useState } from &quot;react&quot;;

interface SearchBarProps {
  programType: &quot;movies&quot; | &quot;series&quot;;
}

export function SearchBar({ programType }: SearchBarProps): JSX.Element {
  const [searchTerm, setSearchTerm] = useState&lt;string&gt;(&quot;&quot;);
  const [selectedYear, setSelectedYear] = useState&lt;number | null&gt;();
  const [counter, setCounter] = useState&lt;number&gt;(0);

  /* 
  Restarts searchTerm and selectedYear when programType prop changes
  */
  useEffect(() =&gt; {
    searchTerm != &quot;&quot; &amp;&amp; setSearchTerm(&quot;&quot;);
    typeof selectedYear == &quot;number&quot; &amp;&amp; setSelectedYear(null);
  }, [programType]);

  const increase = () =&gt; {
    setCounter(counter =&gt; counter + 1);
  };

  return (
    &lt;div className=&quot;search-bar&quot;&gt;
      &lt;p&gt;{searchTerm}&lt;/p&gt;
      &lt;p&gt;{selectedYear}&lt;/p&gt;
      &lt;span className=&quot;counter__output&quot;&gt;{counter}&lt;/span&gt;
      &lt;div className=&quot;btn__container&quot;&gt;
        &lt;button onClick={increase}&gt;+&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

Is there any way of removing the useEffect without affecting the component behavior?

答案1

得分: 1

抱歉,你是对的,在 useEffect 中尝试调用它,像这样:

import { useEffect, useState } from "react";

interface SearchBarProps {
  programType: "movies" | "series";
}

export function SearchBar({ programType }: SearchBarProps): JSX.Element {
  const [searchTerm, setSearchTerm] = useState<string>("");
  const [selectedYear, setSelectedYear] = useState<number | null>();
  const [counter, setCounter] = useState<number>(0);

  const handleProgramTypeChange = () => {
    setSearchTerm("");
    setSelectedYear(null);
  };

  const increase = () => {
    setCounter(counter => counter + 1);
  };

  useEffect(() => {
    handleProgramTypeChange();
  }, [programType]);

  return (
    <div className="search-bar">
      <p>{searchTerm}</p>
      <p>{selectedYear}</p>
      <span className="counter__output">{counter}</span>
      <div className="btn__container">
        <button onClick={increase}>+</button>
      </div>
    </div>
  );
}
英文:

Im sorry, youre right, try calling it within the useEffect, like this:

import { useEffect, useState } from &quot;react&quot;;

interface SearchBarProps {
  programType: &quot;movies&quot; | &quot;series&quot;;
}

export function SearchBar({ programType }: SearchBarProps): JSX.Element {
  const [searchTerm, setSearchTerm] = useState&lt;string&gt;(&quot;&quot;);
  const [selectedYear, setSelectedYear] = useState&lt;number | null&gt;();
  const [counter, setCounter] = useState&lt;number&gt;(0);

  const handleProgramTypeChange = () =&gt; {
    setSearchTerm(&quot;&quot;);
    setSelectedYear(null);
  };

  const increase = () =&gt; {
    setCounter(counter =&gt; counter + 1);
  };

  useEffect(() =&gt; {
    handleProgramTypeChange();
  }, [programType]);

  return (
    &lt;div className=&quot;search-bar&quot;&gt;
      &lt;p&gt;{searchTerm}&lt;/p&gt;
      &lt;p&gt;{selectedYear}&lt;/p&gt;
      &lt;span className=&quot;counter__output&quot;&gt;{counter}&lt;/span&gt;
      &lt;div className=&quot;btn__container&quot;&gt;
        &lt;button onClick={increase}&gt;+&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

答案2

得分: 0

我更新了代码,删除了useEffect,并引入了一个名为handleProgramTypeChange的新函数。每当programType属性发生变化时,该函数被调用,直接将searchTerm设置为空字符串,将selectedYear设置为null。这实现了与先前的useEffect相同的行为,但不使用单独的效果钩子。

import { useState } from "react";

interface SearchBarProps {
  programType: "movies" | "series";
}

export function SearchBar({ programType }: SearchBarProps): JSX.Element {
  const [searchTerm, setSearchTerm] = useState<string>("");
  const [selectedYear, setSelectedYear] = useState<number | null>();
  const [counter, setCounter] = useState<number>(0);

  const handleProgramTypeChange = () => {
    setSearchTerm("");
    setSelectedYear(null);
  };

  const increase = () => {
    setCounter(counter => counter + 1);
  };

  return (
    <div className="search-bar">
      <p>{searchTerm}</p>
      <p>{selectedYear}</p>
      <span className="counter__output">{counter}</span>
      <div className="btn__container">
        <button onClick={increase}>+</button>
      </div>
    </div>
  );
}
英文:

I updated the code, I removed the useEffect and introduced a new function called handleProgramTypeChange. This function is called whenever the programType prop changes, and it directly sets the searchTerm to an empty string and selectedYear to null. This achieves the same behavior as the previous useEffect, but without using a separate effect hook.

import { useState } from &quot;react&quot;;

interface SearchBarProps {
  programType: &quot;movies&quot; | &quot;series&quot;;
}

export function SearchBar({ programType }: SearchBarProps): JSX.Element {
  const [searchTerm, setSearchTerm] = useState&lt;string&gt;(&quot;&quot;);
  const [selectedYear, setSelectedYear] = useState&lt;number | null&gt;();
  const [counter, setCounter] = useState&lt;number&gt;(0);

  const handleProgramTypeChange = () =&gt; {
    setSearchTerm(&quot;&quot;);
    setSelectedYear(null);
  };

  const increase = () =&gt; {
    setCounter(counter =&gt; counter + 1);
  };

  return (
    &lt;div className=&quot;search-bar&quot;&gt;
      &lt;p&gt;{searchTerm}&lt;/p&gt;
      &lt;p&gt;{selectedYear}&lt;/p&gt;
      &lt;span className=&quot;counter__output&quot;&gt;{counter}&lt;/span&gt;
      &lt;div className=&quot;btn__container&quot;&gt;
        &lt;button onClick={increase}&gt;+&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

huangapple
  • 本文由 发表于 2023年7月7日 04:00:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76632196.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定