我应该在哪里声明在 useEffect() 钩子中调用的函数?

IT技术 javascript reactjs react-hooks use-effect
2021-04-05 07:22:32

因此,当使用useEffect调用依赖于状态的函数时,我有以下情况

例子:

// INSIDE APP COMPONENT

const [someState, setSomeState] = React.useState(0);
const [someTrigger, setSomeTrigger] = React.useState(false);

function someFunction() {
  return someState + 1;  
}

React.useEffect(() => {

  const newState = someFunction();  // 'someFunction' IS BEING CALLED HERE
  setSomeState(newState);

},[someTrigger])

问题:

在这种情况下,我应该someFunction在内部声明useEffect()还是将其放在外面(但在组件的主体内部)是否安全?

我可以将它添加到dependency数组中,但它会损害我的代码的可红性,因为我想专注于trigger.

由于useEffect()将在新渲染后运行,假设它将拥有我在其中调用的函数的新副本是否安全?

关于何时应该在useEffect钩子内声明函数或何时必须将其添加到依赖项数组中,是否有基本规则

编辑:请注意,useEffect有这些函数的新副本是必要的,因为这些函数需要访问一些新的最新state变量。

笔记:

此代码在CodeSandbox触发以下eslint 警告虽然它工作得很好。

React Hook React.useEffect 缺少一个依赖项:'someFunction'。包括它或删除依赖项数组。(react-hooks/exhaustive-deps)eslint

真实案例:

这是一个简化的例子。在我的真实案例中,这是一个带有过滤器组件的产品搜索页面。所以当我点击一个过滤器来激活它(比如说,price <= 50)时,我触发了一个useEffect()正在“监听”activePriceFilters状态变量的。然后该效果调用一个函数(someFunction在示例中),该函数将计算filteredList并使用 new 设置新productList状态filteredList

片段

function App() {
  
  const [someState, setSomeState] = React.useState(0);
  const [someTrigger, setSomeTrigger] = React.useState(false);
  
  function someFunction() {
    return someState + 1;  
  }
  
  React.useEffect(() => {
  
    const newState = someFunction();
    setSomeState(newState);
  
  },[someTrigger])
  
  return(
    <React.Fragment>
      <div>I am App</div>
      <div>My state: {someState}</div>
      <button onClick={()=>setSomeTrigger((prevState) => !prevState)}>Click</button>
    </React.Fragment>
  );
}

ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>

2个回答

在 useEffect 内部或外部定义函数的决定取决于调用所有函数的位置。

如果您的函数仅在 useEffect 中被调用,那么在 useEffect 中定义它是有意义的。

但是,从 useEffect 以及其他事件处理程序或其他效果中调用相同的函数,您需要在 useEffect 之外定义它

附注。在您的情况下,您只是更新不需要定义单独函数的状态

function App() {
  
  const [someState, setSomeState] = React.useState(0);
  const [someTrigger, setSomeTrigger] = React.useState(false);
  

  React.useEffect(() => {
    setSomeState(oldState => oldState + 1);
  
  },[someTrigger])
  
  return(
    <React.Fragment>
      <div>I am App</div>
      <div>My state: {someState}</div>
      <button onClick={()=>setSomeTrigger((prevState) => !prevState)}>Click</button>
    </React.Fragment>
  );
}

ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>

就你的场景而言,你会这样写

useEffect(() => {
    const calcVal = (oldState) => {
         // calculate previous state based on oldState
    }

    setSomeState(calcVal);
}, [activePriceFilters])
正如我所说,如果函数将在 useEffect 之外使用,则需要在 useEffect 之外定义一个单独的函数,否则在 useEffect 中定义它并将其传递给状态更新
2021-05-31 07:22:32
该示例是我的真实案例场景的过度简化版本。
2021-06-01 07:22:32
你能帮我解决真实的案例吗?这是一个带有过滤器组件的产品搜索页面。所以当我点击一个过滤器来激活它(比如,价格 <= 50)时,我触发了一个 useEffect(),它正在“监听”activePriceFilters 状态变量。然后该效果调用一个函数(在示例中为 someFunction),该函数将计算filteredList 并使用新的filteredList 设置新的productList 状态。这种方法有什么问题吗?你会如何处理这件事?谢谢!
2021-06-12 07:22:32
谢谢!但是从我的整体代码模式来看,您认为这是一个好方法吗?使用 auseEffect来“监听”状态过滤器变量的变化并调用一个函数来为filteredList? 抱歉打扰你。你的回答真的很有帮助。
2021-06-13 07:22:32

设置另一个状态根本不应该产生影响。

 const [someState, setSomeState] = React.useState(0);

 function incrementState() {
    setSomeState(someState => someState + 1);
 }
你能帮我解决真实的案例吗?这是一个带有过滤器组件的产品搜索页面。所以当我点击一个过滤器来激活它(比如说,price <= 50)时,我触发了一个useEffect()正在“监听”activePriceFilters状态变量的。然后该效果调用一个函数(someFunction在示例中),该函数将计算filteredList并使用 new 设置新productList状态filteredList这种方法有什么问题吗?你会如何处理这件事?谢谢!
2021-05-28 07:22:32
那我就做 const [filters, setFilters] = useState([]); const result = data.filter(filters /*...*/);
2021-05-31 07:22:32
它是同步的。我还应该补充一点,我有 1 个以上的组件过滤器,以及多个具有不同活动过滤器的状态变量。如果它们中的任何一个发生变化,我应该计算一个filteredList作为道具传递给我的ResultList组件的新状态
2021-06-01 07:22:32
是的,在那种情况下。
2021-06-15 07:22:32
它是否同步计算它们?或者它是否从服务器检索它们?
2021-06-21 07:22:32