Функции в компонентах без гражданства?

Я пытаюсь преобразовать эту классную анимацию <canvas> я нашел здесь, в повторно используемый компонент React. Похоже, что для этого компонента потребуется один родительский компонент для холста и много дочерних компонентов для function Ball().

По соображениям производительности, вероятно, было бы лучше превратить Balls в компоненты без состояния, так как их будет много. Я не так хорошо знаком с созданием компонентов без сохранения состояния, и мне было интересно, где я должен определить функции this.update() и this.draw, которые определены в function Ball().

Функции для компонентов без состояния идут внутри компонента или снаружи? Другими словами, что из следующего лучше?

1:

const Ball = (props) => {
    const update = () => {
        ...
    }

    const draw = () => {
        ...
    }

    return (
       ...
    );
}

2:

function update() {
     ...
}

function draw() {
     ...
}

const Ball = (props) => {
    return (
       ...
    );
}

Каковы плюсы/минусы каждого из них и являются ли они лучше для конкретных случаев использования, таких как мой?

Ответ 1

Прежде всего следует отметить, что функциональные компоненты без состояния не могут иметь методы, вы не должны рассчитывать на вызов update или draw на рендеринге Ball, если это функциональный компонент без состояния.

В большинстве случаев вы должны объявлять функции вне функции компонента, поэтому вы объявляете их только один раз и всегда повторно используете одну и ту же ссылку. Когда вы объявляете функцию внутри, каждый раз, когда компонент отображается, функция будет определена снова.

Есть случаи, когда вам нужно определить функцию внутри компонента, например, назначить ее как обработчик события, который ведет себя по-разному на основе свойств компонента. Но вы можете определить функцию вне Ball и связать ее со свойствами, делая код намного чище и делая функции update или draw повторно используемыми.

// You can use update somewhere else
const update (propX, a, b) => { ... };

const Ball = props => (
  <Something onClick={update.bind(null, props.x)} />
);

вместо:

const Ball = props => {
  function update(a, b) {
    // props.x is visible here
  }

  return (
    <Something onClick={update} />
  );
}

Ответ 2

Мы можем иметь функции внутри функциональных компонентов без сохранения состояния, ниже приведен пример:

 const Action = () => {
  function  handlePick(){
     alert("test");
  }
  return (
    <div>
      <input type="button" onClick={handlePick} value="What you want to do ?" />
    </div>
  );
}

Но это не очень хорошая практика, так как функция handlePick() будет определяться каждый раз, когда вызывается компонент.

Ответ 3

2: это хорошо, но есть трагедия, когда вы хотите использовать реквизит.

Лучшая практика - использовать функции useHooks, такие как функция useCallback.

импортировать они из реагирующей библиотеки.

Ответ 4

Мы можем использовать ловушку React useCallback, как показано ниже в функциональном компоненте:

const home = (props) => {
    const { small, img } = props
    const [currentInd, setCurrentInd] = useState(0);
    const imgArrayLength = img.length - 1;
    useEffect(() => {
        let id = setInterval(() => {
            if (currentInd < imgArrayLength) {
                setCurrentInd(currentInd => currentInd + 1)
            }
            else {
                setCurrentInd(0)
            }
        }, 5000);
        return () => clearInterval(id);
    }, [currentInd]);
    const onLeftClickHandler = useCallback(
        () => {
            if (currentInd === 0) {

            }
            else {
                setCurrentInd(currentInd => currentInd - 1)
            }
        },
        [currentInd],
    );

    const onRightClickHandler = useCallback(
        () => {
            if (currentInd < imgArrayLength) {
                setCurrentInd(currentInd => currentInd + 1)
            }
            else {

            }
        },
        [currentInd],
    );
    return (
        <Wrapper img={img[currentInd]}>
            <LeftSliderArrow className={currentInd > 0 ? "red" : 'no-red'} onClick={onLeftClickHandler}>
                <img src={Icon_dir + "chevron_left_light.png"}></img>
            </LeftSliderArrow>
            <RightSliderArrow className={currentInd < imgArrayLength ? "red" : 'no-red'} onClick={onRightClickHandler}>
                <img src={Icon_dir + "chevron_right_light.png"}></img>
            </RightSliderArrow>
        </Wrapper>);
}

export default home;

Я получаю 'img' от этого родителя, и это массив.