React - Як змусити візуалізувати функціональний компонент?


86

У мене є функціональний компонент, і я хочу змусити його повторно відтворити.

Як я можу це зробити?
Оскільки екземпляра немає this, я не можу зателефонувати this.forceUpdate().


ні, компонент без громадянства не має стану. Замість цього використовуйте клас
TryingToImprove

2
Ви справді маєте на увазі "компонент без громадянства ", а не "функціональний компонент" ?
Кріс

2
Щоб оновити компонент без стану, переданий реквізит потрібно змінити.
fungusanthrax

поруч з реквізитом ви можете використовувати гачок useState, а компоненти будуть відтворюватися повторно, коли він зміниться
Hamid Shoja

Відповіді:


134

🎉 Тепер ви можете, використовуючи гачки React

Використовуючи реакційні гачки, тепер ви можете викликати useState()свій функціональний компонент.

useState()поверне масив із 2 речей:
1. Значення, що представляє поточний стан.
2. Її сетер. Використовуйте його для оновлення значення.

Оновлення значення за допомогою його установника змусить ваш функціональний компонент повторно відтворити ,
як forceUpdateце робить:

import React, { useState } from 'react';

//create your forceUpdate hook
function useForceUpdate(){
    const [value, setValue] = useState(0); // integer state
    return () => setValue(value => ++value); // update the state to force render
}

function MyComponent() {
    // call your hook here
    const forceUpdate = useForceUpdate();

    return (
        <div>
            {/*Clicking on the button will force to re-render like force update does */}
            <button onClick={forceUpdate}>
                Click to re-render
            </button>
        </div>
    );
}

Демо-версію ви можете знайти тут .

Компонент вище використовує спеціальну функцію хука ( useForceUpdate), яка використовує логічний стан хука ( useState). Він перемикає логічний стан і таким чином вказує React повторно запустити функцію візуалізації.

РЕДАГУВАТИ

У старій версії цієї відповіді фрагмент використовував логічне значення та вмикав його forceUpdate(). Тепер, коли я відредагував свою відповідь, фрагмент використовує число, а не логічне значення.

Чому? (ви б запитали мене)

Оскільки одного разу зі мною трапилося, що мою forceUpdate()викликали двічі згодом із 2 різних подій, і, таким чином, вона скидала булеве значення у вихідному стані, і компонент ніколи не відображався.

Тому що в програмі useStateвстановлення ( setValueтут) Reactпорівняйте попередній стан з новим і обробляйте, лише якщо стан інший.


3
Ніщо на цій сторінці не містить жодної інформації про використання хуків для дзвінків forceUpdate.
jdelman

1
На даний момент ви маєте рацію, це краще, оскільки, навіть міцні гачки ще не випущені, ви все одно можете використовувати його в бета-версії. Але після їх випуску немає жодної причини, що компонент класу буде кращим. Використання хуків робить код чистішим, ніж компонент класу, як показано на відео нижче в реакційному конфігурації. У будь-якому випадку, питання полягає в тому, чи можливо це. Відповідь тепер змінюється з "Ні" на "Так" через гачки. youtube.com/watch?v=wXLf18DsV-I
Yairopro

1
Привіт @DanteTheSmith. Під "Найвищим рівнем" це означає, що хуки не повинні викликатися зсередини умови або циклу, як ви сказали. Але я можу сказати вам, що ви можете зателефонувати їм з іншої функції. А це означає створення власного гачка. Ден Абрамов, представляючи хуки React у React conf, наочно демонструє, що це найчистіший та найкращий спосіб поділитися логікою між функціональними компонентами: youtu.be/dpw9EHDh2bM?t=2753
Яйропро

1
Немає необхідності перемикати будь-який стан "примусово відтворювати". Ви створюєте хибне враження, що React "порівнює" значення попереднього та наступного стану, щоб вирішити, чи потрібно його повторно відтворювати. Хоча це точно не так.
meandre

1
@meandre Так, це точно порівнює. Ми говоримо про useStateхук, а не про клас ', setStateякий справді не робить порівняння (якщо ви не реалізуєте метод shouldUpdate). Подивіться ту саму демонстраційну демонстрацію, яку я опублікував, але зі статичним значенням, що використовується для setState, вона не відображається знову: codesandbox.io/s/determined-rubin-8598l
Yairopro

47

Реакція оновлення v16.8 (випуск 16 лютого 2019 р.)

Оскільки реакція 16.8, випущена за допомогою гачків , функціональні компоненти тепер мають здатність утримувати стійкість state. З цією здатністю ви можете тепер імітують A forceUpdate:

Зверніть увагу, що цей підхід слід переглянути і в більшості випадків, коли вам потрібно примусити оновити, ви, мабуть, робите щось не так.


До реагування 16.8.0

Ні, ви не можете, функціональні компоненти без станів - це звичайна норма, functionsяка повертається jsx, у вас немає доступу до методів життєвого циклу React, оскільки ви не поширюєтеся на React.Component.

Подумайте про функцію-компонент як про renderчастину методу компонентів класу.


часто можна. змінити реквізит, що до нього приходить
Маріан Зеке Шедай

5
це не примушує рендеринг, це просто звичайний рендер. коли ви хочете примусити візуалізацію, це зазвичай випадок, коли ви хочете запустити метод візуалізації, коли він не був розроблений для запуску, наприклад, коли немає нових propsабо stateзмін. ви не можете примусити функцію візуалізації, оскільки функція не існує renderна компонентах без стану. Безкомпонентні компоненти - це не extends React.Componentпросто функції, які повертаються jsx.
Сагів bg

Реквізит для "коли вам потрібно примусити оновлення, ви, мабуть, робите щось не так" - я знав, що це так, але це просто спонукало мене ще раз уважно поглянути на мій хук useEffect.
Methodician

12

Офіційне поширене запитання ( https://reactjs.org/docs/hooks-faq.html#is-there-something-like-forceupdate ) зараз рекомендує такий спосіб, якщо вам дійсно потрібно це зробити:

  const [ignored, forceUpdate] = useReducer(x => x + 1, 0);

  function handleClick() {
    forceUpdate();
  }

Ну, я ніколи цього не знав
Чаріт Джаясанка,

9
і ви можете скоротити свій код на 7 байт і не створювати невикористовувану змінну:const [, forceUpdate] = useReducer(x => x + 1, 0);
Костянтин Смолянін

7

Я використовував сторонню бібліотеку під назвою use-force-update, щоб змусити зробити мої реакційні функціональні компоненти. Працював як шарм. Просто використовуйте пакет імпорту у своєму проекті та використовуйте так.

import useForceUpdate from 'use-force-update';

const MyButton = () => {

  const forceUpdate = useForceUpdate();

  const handleClick = () => {
    alert('I will re-render now.');
    forceUpdate();
  };

  return <button onClick={handleClick} />;
};

2
Щоб заощадити ваш клік - useForceUpdateвикористовує, useCallbackяк згадано в інших відповідях. Ця бібліотека - лише службова бібліотека, щоб заощадити кілька натискань клавіш.
asyncwait

О, дякую. Я цього не знав. :)
Charith Jayasanka

6

Застереження: НЕ ВІДПОВІДЬ НА ПРОБЛЕМУ.

Залишаючи тут важливу примітку:

Якщо ви намагаєтесь оновити компонент без громадянства, швидше за все, щось не так з вашим дизайном.

Розглянемо такі випадки:

  1. Передайте сеттер (setState) дочірньому компоненту, який може змінити стан і призвести до повторного відтворення батьківського компонента.
  2. Подумайте про стан підйому
  3. Розгляньте можливість розміщення цього стану у вашому магазині Redux, яке може автоматично примусити повторно відтворити підключені компоненти.

1
У мене є випадок, коли мені потрібно було вимкнути оновлення компонентів і примусити його, коли я хочу (це рухома лінійка, яка оновлює свою цінність при кожному русі, і оновлення викликали мерехтливу поведінку). Тому я вирішив використовувати класи для цього компонента, і я рекомендую, щоб усі компоненти, які потребують глибокого контролю над поведінкою візуалізації, мали виконуватися в класах, оскільки в даний час хуки не забезпечують точного контролю над цією поведінкою. (поточна версія React - 16.12)
Майкл Уоллес

Я думав те саме, але, я хотів швидкого виправлення, тому використовував примусове оновлення.
Charith Jayasanka

У реальному світі це використовують. Ніщо ніколи не буває ідеальним, і якщо ви коли-небудь захочете випустити програмне забезпечення, вам краще знати, як змусити щось відбуватися, коли хтось інший їх псує.
Brain2000

1

Це можна зробити без явного використання хуків за умови, що ви додаєте prop до свого компонента та стан до батьківського компонента компонента без стану:

const ParentComponent = props => {
  const [updateNow, setUpdateNow] = useState(true)

  const updateFunc = () => {
    setUpdateNow(!updateNow)
  }

  const MyComponent = props => {
    return (<div> .... </div>)
  }

  const MyButtonComponent = props => {
    return (<div> <input type="button" onClick={props.updateFunc} />.... </div>)
  }

  return (
    <div> 
      <MyComponent updateMe={updateNow} />
      <MyButtonComponent updateFunc={updateFunc}/>
    </div>
  )
}

1

Прийнята відповідь хороша. Тільки для того, щоб було легше зрозуміти.

Приклад компонента:

export default function MyComponent(props) {

    const [updateView, setUpdateView] = useState(0);

    return (
        <>
            <span style={{ display: "none" }}>{updateView}</span>
        </>
    );
}

Щоб примусити повторний візуалізацію, зателефонуйте нижче:

setUpdateView((updateView) => ++updateView);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.