跳过在初始化时更改钩子(useEffect)

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

Skip hook change (useEffect) on initialize

问题

以下是你提供的代码的中文翻译部分:

// 创建了一个带有下拉框的函数组件。每当用户选择新值时,我会发送一个事件给消费组件。
// 我正在使用 hooks 来处理选定的索引。我意识到 hooks 是异步的。
// 当选择新值时,旧值会被发送到消费组件。所以我开始使用 "useEffect"。
// 但是 useEffect 有一个副作用,它在变量初始化时调用。
// 有没有办法告诉 REACT 在初始化时不发送事件给 useEffect,以便我不会在初始化时发送选定更改事件?
// 你只需添加一个布尔变量(比如 hasBeenInit),还是有更聪明的方法?

import React, { useState, useEffect } from "react";
import {
  Dropdown,
  DropdownToggle,
  DropdownMenu,
  DropdownItem,
  Button
} from "reactstrap";

const DropdownPaging = props => {
  const [selectedValue, setSelectedValue] = useState(10);
  const [dropdownOpen, setDropdownOpen] = useState(false);
  const [pageIndex, setPageIndex] = useState(0);

  const toggle = () => setDropdownOpen(prevState => !prevState);

  function dropDownChanged(val) {
    setSelectedValue(val);
  }

  useEffect(() => {
    triggerEventChange(selectedValue, pageIndex);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selectedValue, pageIndex]);

  function pageIndexIncremented() {
    setPageIndex(counter => counter + 1);
  }

  function pageIndexDecremented() {
    if (pageIndex >= 1) {
      setPageIndex(counter => counter - 1);
    } else {
      setPageIndex(0);
    }
  }

  function triggerEventChange(take, index) {
    if (props.valueChanged) {
      props.valueChanged({ take: take, pageIndex: index });
    } else {
    }
  }

  return (
    <div>
      <table>
        <tr>
          <td>
            <Button
              outline
              disabled={pageIndex === 0}
              color="dark"
              onClick={pageIndexDecremented}
            >
              &lt;
            </Button>
          </td>
          <td>{pageIndex}</td>
          <td>
            <Button outline color="dark" onClick={pageIndexIncremented}>
              &gt;
            </Button>
          </td>
          <td>
            <Dropdown isOpen={dropdownOpen} toggle={toggle}>
              <DropdownToggle caret outline color="dark">
                {selectedValue}
              </DropdownToggle>
              <DropdownMenu>
                <DropdownItem onClick={() => dropDownChanged(10)}>
                  10
                </DropdownItem>
                <DropdownItem onClick={() => dropDownChanged(25)}>
                  25
                </DropdownItem>
                <DropdownItem onClick={() => dropDownChanged(50)}>
                  50
                </DropdownItem>
                <DropdownItem onClick={() => dropDownChanged(100)}>
                  100
                </DropdownItem>
              </DropdownMenu>
            </Dropdown>
          </td>
        </tr>
      </table>
    </div>
  );
};

export default DropdownPaging;

请注意,这只是代码的翻译部分,不包括任何额外的解释或回答问题。如果你需要进一步的信息或解释,请随时提出。

英文:

I have created a function component with a dropdown. Everytime the user selects a new value i send an event to consuming component. I am using hooks for the selected index. I realized that hooks works async. When a new value was selected the old value was posted to the consuming component. So I started using "useEffect". However useEffect has that side effect that it is called when the variable is initialized. Is there anyway to tell REACT not to send an event to useEffect on initialization so I dont send a selected change event on initialization? Do you just add a boolean variable (like hasBeenInit) or is there something smarter?

https://codesandbox.io/s/blissful-clarke-ky1nr?fontsize=14&amp;hidenavigation=1&amp;theme=dark

import React, { useState, useEffect } from &quot;react&quot;;
import {
Dropdown,
DropdownToggle,
DropdownMenu,
DropdownItem,
Button
} from &quot;reactstrap&quot;;
const DropdownPaging = props =&gt; {
const [selectedValue, setSelectedValue] = useState(10);
const [dropdownOpen, setDropdownOpen] = useState(false);
const [pageIndex, setPageIndex] = useState(0);
const toggle = () =&gt; setDropdownOpen(prevState =&gt; !prevState);
function dropDownChanged(val) {
setSelectedValue(val);
}
useEffect(() =&gt; {
triggerEventChange(selectedValue, pageIndex);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedValue, pageIndex]);
function pageIndexIncremented() {
setPageIndex(counter =&gt; counter + 1);
}
function pageIndexDecremented() {
if (pageIndex &gt;= 1) {
setPageIndex(counter =&gt; counter - 1);
} else {
setPageIndex(0);
}
}
function triggerEventChange(take, index) {
if (props.valueChanged) {
props.valueChanged({ take: take, pageIndex: index });
} else {
}
}
return (
&lt;div&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;Button
outline
disabled={pageIndex === 0}
color=&quot;dark&quot;
onClick={pageIndexDecremented}
&gt;
&amp;lt;
&lt;/Button&gt;
&lt;/td&gt;
&lt;td&gt;{pageIndex}&lt;/td&gt;
&lt;td&gt;
&lt;Button outline color=&quot;dark&quot; onClick={pageIndexIncremented}&gt;
&amp;gt;
&lt;/Button&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;Dropdown isOpen={dropdownOpen} toggle={toggle}&gt;
&lt;DropdownToggle caret outline color=&quot;dark&quot;&gt;
{selectedValue}
&lt;/DropdownToggle&gt;
&lt;DropdownMenu&gt;
&lt;DropdownItem onClick={() =&gt; dropDownChanged(10)}&gt;
10
&lt;/DropdownItem&gt;
&lt;DropdownItem onClick={() =&gt; dropDownChanged(25)}&gt;
25
&lt;/DropdownItem&gt;
&lt;DropdownItem onClick={() =&gt; dropDownChanged(50)}&gt;
50
&lt;/DropdownItem&gt;
&lt;DropdownItem onClick={() =&gt; dropDownChanged(100)}&gt;
100
&lt;/DropdownItem&gt;
&lt;/DropdownMenu&gt;
&lt;/Dropdown&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
);
};
export default DropdownPaging;

答案1

得分: 5

你可以使用 useRef 来模拟组件是否已挂载,这样你的组件就变成了:

const mounted = useRef(false);
const toggle = () => setDropdownOpen(prevState => !prevState);

function dropDownChanged(val) {
  setSelectedValue(val);
}

useEffect(() => {
  if (mounted.current) {
    triggerEventChange(selectedValue, pageIndex);
  } else {
    mounted.current = true;
  }

  // eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedValue, pageIndex]);

更新的示例链接https://codesandbox.io/s/dropdownpager-urvrp
英文:

You could use useRef to simulated whether the component has mounted or not, so your component becomes :

  const mounted = useRef(false);
const toggle = () =&gt; setDropdownOpen(prevState =&gt; !prevState);
function dropDownChanged(val) {
setSelectedValue(val);
}
useEffect(() =&gt; {
if (mounted.current) {
triggerEventChange(selectedValue, pageIndex);
} else {
mounted.current = true;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedValue, pageIndex]);

updated sandbox: https://codesandbox.io/s/dropdownpager-urvrp

答案2

得分: 1

以下是翻译好的部分:

布尔值是一个选项。如果您需要在应用程序的其他地方使用此行为,您可以创建一个自定义钩子:

const useEffectIgnoringInit = (回调, 监听的值) => {
  const [已初始化, 设置已初始化] = useState(true);
  useEffect(() => {
    if (已初始化) {
      回调();
    } else {
      设置已初始化(true);
    }
  }, 监听的值);
}

然后您可以在代替 useEffect 使用它

```jsx
useEffectIgnoringInit(() => {
  触发事件更改(selectedValue, pageIndex);
  // eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedValue, pageIndex]);
英文:

The boolean value is an option. If you need the behavior in other places in your app you can create a custom hook:

const useEffectIgnoringInit = (callBack, watchedValues) =&gt; {
const [hasBeenInit, setHasBeenInit] = useState(true);
useEffect(() =&gt; {
if(hasBeenInit){
callBack();
} else {
setHasBeenInit(true);
}
}, watchedValues);
}

Then you use it instead of useEffect:

useEffectIgnoringInit(() =&gt; {
triggerEventChange(selectedValue, pageIndex);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedValue, pageIndex]);

huangapple
  • 本文由 发表于 2020年1月7日 00:23:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/59615551.html
匿名

发表评论

匿名网友

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

确定