Как заставить React (функциональный компонент с использованием хуков) создать новый компонент с нуля при смене реквизита? - PullRequest
2 голосов
/ 27 марта 2019

TLDR

Есть ли способ заставить React воссоздать компонент ( функциональный компонент, использующий перехватчики ) с нуля, вместо повторного рендеринга его на prop изменить?

РЕДАКТИРОВАТЬ

Атрибут ключа работает.У меня была проблема из-за последовательности обновления состояния, которую я делал.Первое обновление сразу пыталось отобразить компонент, для которого необходимо было выполнить последнее обновление.

Я работаю над компонентом под названием <AddProductWidget>, который получит следующую props информацию о продукте и должна отобразить его детали.Он принадлежит странице со строкой поиска, в которую вы вводите productID, и получает данные о продукте из облачной функции.

Он отображается следующим образом:

  <AddProductWidget
    userImages={props.productDetails.userImages}    // Array of strings (urls)
    title={props.productDetails.title}
    stars={props.productDetails.stars}
  />

AddProductWidget.js

Отображает компонент <UserImages>, который позволяет пользователю щелкнуть некоторые изображения, чтобы выбрать их перед сохранением в базе данных.Поэтому ему нужно было state, чтобы «запомнить», какие изображения были нажаты пользователем.

function AddProductWidget(props) {

  const [userImagesSelected, setUserImagesSelected] = useState(
    () => {
      if (props.userImages && props.userImages > 0) {
        return new Array(props.userImages.length).fill(false);
      }
      return null;
    }
  );

  // IT renders the <UserImages> component
  // The code here is simplified

  return(
      <UserImages
        userImages={props.userImages}
        userImagesSelected={userImagesSelected}
        setUserImagesSelected={setUserImagesSelected}
      />
  );

}

Начальное состояние этого массива userImagesSelected должно быть такой же длины массива userImages изаполнить false значениями, которые станут true, как только пользователь начнет нажимать на изображения.Если у продукта нет пользовательских изображений, props.userImages будет null и userImagesSelected также должно быть null.

Все работает, как ожидалось, когда я загружаю первый продукт.Независимо от того, есть ли у него изображения или нет, все отображается правильно.

Проблема:

Проблема заключается в том, когда я загружаю продукт с нулевыми изображениями, а затем загружаюдругой продукт с 5 изображениями, например.По существу, props для AddProductWidget изменится (поскольку он получил новый продукт), но, поскольку кажется, что React пытается использовать тот же экземпляр компонента, я получаю сообщение об ошибке, потому что мой компонент UserImages попытается отобразитьинформация о выбранных изображениях, но состояние userImagesSelected по-прежнему будет null, поскольку в последних продуктах не было изображений.

Когда я работал с классами, я мог заставить React воссоздать экземпляр компонента, используяkey атрибут, но, похоже, он не работает с хуками, поскольку следующий код не решил мою проблему:

  <AddProductWidget
    key={productID}
    userImages={props.productDetails.userImages}    // Array of strings (urls)
    title={props.productDetails.title}
    stars={props.productDetails.stars}
  />

Вопрос

IsЕсть ли способ заставить React воссоздать компонент ( функциональный компонент с использованием хуков ) с нуля, вместо того, чтобы повторно визуализировать его при изменении prop?

Extra

A нашел способ обойти это, но это кажется немного хакерским, даже несмотря на то, что он есть в React docs.Он в основном использует состояние для обнаружения изменения props и вызывает setState() во время рендеринга.Я хотел бы, чтобы лучше было воссоздать мой компонент с нуля.

Часто задаваемые вопросы по хукам: как мне реализовать getDerivedStateFromProps

1 Ответ

2 голосов
/ 27 марта 2019

Не уверен, как вы решили, что другой key не будет перемонтировать компонент, но он должен это сделать (вы уверены, что ключ изменился?)

Вот пример, показывающий это

function Test() {
  React.useEffect(() => {
    console.log('Test was mounted');
    return () => {
      console.log('Test was un-mounted');
    };
  }, []);

  return "hi there, I'm Test";
}

function App() {
  const [val, setVal] = React.useState("Change me...");
  return (
    <div className="App">
      <input value={val} onChange={e => setVal(e.target.value)} />
      <br />
      <Test key={val} />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root" />
...