Как сделать так, чтобы функция вызывалась только один раз после рендеринга?

#javascript #reactjs #jsx

Вопрос:

Как сделать так, чтобы функция extraFunc вызывалась только один раз после рендеринга, потому что при нажатии на счетчик эта функция автоматически вызывается? Заранее спасибо.

 import React, {useState} from "react";
 
export const ProfilerCheckerApp = () => {
    const [counterValue, setCounterValue] = useState(0);
 
    const increase = () => setCounterValue(counterValue   1);
    const decrease = () => setCounterValue(counterValue - 1);
 
    return (
        <>
            <Counter increase={increase} decrease={decrease} value={counterValue}/>
        </>
    )
}
 
const extraFunc = (value) => {
    console.log("ex func works");
    return "value is: "   value;
}
 
const Counter = ({increase = f => f, decrease = f => f, value = 0}) => {
 
    let my_value = extraFunc(value);
 
    return (
        <div>
            <button onClick={increase}> </button>
            <span style={{padding: "10px"}}>{my_value}</span>
            <button onClick={decrease}>-</button>
        </div>
    )
}
 

Комментарии:

1. Что касается: «…потому что, когда вы нажимаете на счетчик, эта функция автоматически вызывается…» . Это потому <Counter/> , что отображается не только один раз, но и каждый раз, когда меняется реквизит или состояние (реквизит здесь). Учитывая ваш код, это происходит каждый <ProfilerCheckerApp /> раз при визуализации. Опять же, потому что это реквизит или изменения состояния (состояние здесь).

2. Учитывая ваши комментарии к приведенным ниже ответам, пожалуйста, расширьте свой вопрос, чтобы включить объяснение, почему вы хотите extraFunc запустить только один раз и что в настоящее время он является просто заполнителем. Предпочтительно, включая некоторый код, который показывает, как будет выглядеть фактическая функция. Тем не менее, учитывая то, что вы написали в своих комментариях, не имеет особого смысла запускать функцию только один раз , но все равно зависеть от изменяющегося значения.

3. Моя дополнительная функция -заполнитель. Ты прав. Нет смысла призывать его. Я просто хочу иметь навык вызова функций один раз после рендеринга.

4. Ну, тогда у вас есть свой ответ, функция уже выполняется ровно один раз за рендеринг, хотя компонент отрисовывается несколько раз. Если это учебный проект, то вам следует потратить некоторое время на изучение соответствующей номенклатуры . Похоже, что на самом деле вам нужно вызвать функцию только для начального рендеринга. Для этого вы бы использовали useEffect , как описано в ответах ниже.

5. Я использовал useEffect без значений в массиве зависимостей, но получил следующее предупреждение: : 'React Hook useEffect has a missing dependency: 'value'. Either include it or remove the dependency array . Когда я делаю так, как указано в предупреждении, приложение работает не так, как я ожидал.

Ответ №1:

Я предполагаю, что вы имели в виду под «автоматическим вызовом функции», когда вы нажимаете на кнопку, вы получаете запрос console.log «ex функция работает». На самом деле, это и есть предполагаемое поведение, потому что каждый раз, когда состояние компонента React обновляется (в данном случае изменение значения из — за нажатия кнопки или -), будет отображаться повторно, и функция extraFunc() будет вызываться снова из этой строки.

 let my_value = extraFunc(value);
 

Вместо того, чтобы передавать функцию extraFunc() и присваивать ее значение переменной my_value, вы можете пропустить все это и напрямую отобразить текст И значение в компоненте счетчика.

Мой способ сделать это-полностью удалить функцию extraFunc (). Вместо этого я бы просто интерполировал текст «ЗНАЧЕНИЕ РАВНО» непосредственно в ваш промежуток.

 import React, { useState } from "react";

export const ProfilerCheckerApp = () => {
  const [counterValue, setCounterValue] = useState(0);

  const increase = () => setCounterValue(counterValue   1);
  const decrease = () => setCounterValue(counterValue - 1);

  return (
    <>
      <Counter increase={increase} decrease={decrease} value={counterValue} />
    </>
  );
};

const Counter = ({ increase, decrease, value }) => {
  return (
    <div>
      <button onClick={increase}> </button>
      <span style={{ padding: "10px" }}>VALUE IS: {value}</span>
      <button onClick={decrease}>-</button>
    </div>
  );
}; 

Кроме того, я переделал ваш реквизит, чтобы он выглядел немного лучше. Вместо того, чтобы делать

 const Counter = ({increase = f => f, decrease = f => f, value = 0}) => {
 

Вы можете просто пойти дальше и сделать это

 const Counter = ({increase, decrease, value}) => {
 

Это очень читабельно, и это то, что на самом деле является общим соглашением. Приложение по-прежнему работает по назначению, вы можете попробовать скопировать и вставить весь этот блок.

Если вам понадобятся какие-либо более подробные объяснения, не стесняйтесь спрашивать

Комментарии:

1. Большое вам спасибо за ваш ответ, но я намеренно вызвал функцию в компоненте, чтобы смоделировать ситуацию, в которой я использовал бы useMemo или useCallback.

2. Я попытался реализовать useMemo или useCallback, но это не сработало. Я решил пойти другим путем использования useEffect с пустым массивом, но я получил предупреждение от WebStorm примерно такого рода: «У React Hook useEffect отсутствует зависимость: «значение». Либо включите его, либо удалите массив зависимостей. Если для «setMyValue» требуется текущее значение «value», вы также можете переключиться на useReducer в разделе useState и прочитать «значение» в разделе «реагирующие крючки/исчерпывающие депы». Хорошо. когда я делаю так, как указано в предупреждении, приложение работает не так, как я ожидал.

Ответ №2:

Я действительно не понимаю, зачем тебе это нужно. Разве my_value значение не должно основываться на обновленном value ? но в любом случае, вы можете это сделать:

 const Counter = ({increase = f => f, decrease = f => f, value = 0}) => {
  const[my_value]  = useState(extraFunc(value));

  return (
      <div>
          <button onClick={increase}> </button>
          <span style={{padding: "10px"}}>{my_value}</span>
          <button onClick={decrease}>-</button>
      </div>
  )
 

}

Ответ №3:

Вы можете использовать useEffect , однако, назначение my_value , а затем переход к визуализации, как {my_value} это проблематично. Я настоятельно рекомендую использовать переменную состояния и для этого.

 import {useState, useEffect} from 'react'

const Counter = ({increase = f => f, decrease = f => f, value = 0}) => {
 
    const [myVal, setMyVal] = useState(null)

    useEffect(() => {
      const my_val = extraFunc(5)
      setMyVal(my_val)
    }, [] /* Empty array makes this useEffect run once only */)

    // Alternative
    useEffect(() => {
      const my_val = extraFunc(value)
      setMyVal(my_val)
    }, [value] /* This will run every time the prop value changes */)
 

    return (
        <div>
            <button onClick={increase}> </button>
            <span style={{padding: "10px"}}>{myVal}</span>
            <button onClick={decrease}>-</button>
        </div>
    )
}
 

Комментарии:

1. Когда я использую пустой массив зависимостей в useEffect, WebStorm всегда показывает мне следующее сообщение: React Hook у useEffect отсутствует зависимость: «значение». Либо включите его, либо удалите массив зависимостей. Когда я делаю так, как указано в предупреждении, приложение работает не так, как я ожидал. Так в чем же дело?

2. Если вы используете value внутри эффекта использования, то это зависимость. Если приложение не работает должным образом после включения этого , я бы предположил, что это, вероятно, ошибка в дизайне, и вам следует пересмотреть то, как вы управляете своим приложением. Потому что, если значение не изменится, эффект использования все равно не будет выполняться, и если он изменится, вы захотите запустить эффект использования, так как хотите использовать обновленное значение

Ответ №4:

Для этого вы можете использовать useEffect Hook, передав пустой массив [] в качестве второго аргумента.
Примечание: Счетчик будет увеличиваться/уменьшаться, но его значение не будет отображаться, так как оно основано на extraFunc том, что выполняется только один раз.

 const {useState, useEffect} = React;

const ProfilerCheckerApp = () => {
    const [counterValue, setCounterValue] = useState(0);
 
    const increase = () => setCounterValue(counterValue   1);
    const decrease = () => setCounterValue(counterValue - 1);
     
    return (
        <div>
            <Counter increase={increase} decrease={decrease} value={counterValue}/>
        </div>
    )
}
 
const extraFunc = (value) => {
    console.log("ex func works");
    return "value is: "   value;
}
 
const Counter = ({increase = f => f, decrease = f => f, value = 0}) => {
      const [myValue, setMyValue] = useState("");
      useEffect(()=>{
         setMyValue(extraFunc(value));
      }, []); 
     
    return (
        <div>
            <button onClick={increase}> </button>
            <span style={{padding: "10px"}}>{myValue}</span>
            <button onClick={decrease}>-</button>
        </div>
    )
}

ReactDOM.render(<ProfilerCheckerApp/>, document.getElementById("main")); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js" integrity="sha512-YMtLFKDKe5a4zi7rJ0y4wdGErKZe3tx7L AXDTxjNDzkv7jsaNhvumeU1xQvw6UqVwBVmYlO9NhsSuSVPUN/xQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.0-alpha-bc4e75112-20210815/umd/react-dom.production.min.js" integrity="sha512-DMCGkVCF04hYYSO4X1mQhMfjdiilNTja3T/NnK02Zs/hsc/jpfnYQ/ Ura375lTzlKrI1z9eoe2X W4P3pmbGg==" crossorigin="anonymous"
  referrerpolicy="no-referrer"></script>


<div id="main"></div> 

Комментарии:

1. @AlexKor5 Вы можете связаться со мной, если у вас возникнут какие-либо проблемы.

2. Итак, я пытался использовать useEffect с пустым массивом зависимостей [], но сразу после этого действия консоль WebStorm всегда показывает мне такое сообщение: React Hook useEffect has a missing dependency: 'value'. Either include it or remove the dependency array. If 'setMyValue' needs the current value of 'value', you can also switch to useReducer instead of useState and read 'value' in the reducer react-hooks/exhaustive-deps