React. Когда функция импорта в функции компонента, я могу знать, почему это не работает ловушки setState ..? - PullRequest
3 голосов
/ 30 октября 2019

Я пытался разделить код для функции вызова, когда это необходимо.

, поэтому я отделил функцию от компонента.

//Split.js
const Split = () => {
  return <div>It`s text</div>;
};

export default Split;

Это работает в компоненте класса React.

//App.js
class App extends Component {
  state = {
    Split: null
  };
  handleClick = () => {
    import("./Split").then(({ default: Split }) => {
      this.setState({
        Split
      });
    });
  };
  render() {
    const { Split } = this.state;
    return (
      <div>
        <button onClick={this.handleClick}>Click Me</button>
        {Split && <Split />}
      </div>
    );
  }
}

вот ссылка на компонент класса (работает) https://codesandbox.io/s/code-splitting-1-bbtpe

Но когда я перешел на компонент функции Hooks, он не работал ..

const App = () => {
  const [split, setSplit] = useState(null);
  const handleClick = () => {
    import("./Split").then(({ default: Split }) => {
      // console.log(SplitMe());
      setSplit(Split);
    });
  };

  const SplitMe = split;
  return (
    <div>
      <button onClick={handleClick}>Click Me</button>
      {SplitMe && <SplitMe />}
    </div>
  );
};

и вызванная ошибка

Ошибка: недопустимый тип элемента: ожидается строка (для встроенных компонентов) или класс / функция (для составных компонентов), но получено: object.

здесь компонент функцииссылка (рабочая) https://codesandbox.io/s/code-splitting-2-4flbm

Могу ли я узнать, что такое setState компонента класса с setState (hook) компонента функции?

спасибо!

Ответы [ 3 ]

2 голосов
/ 30 октября 2019

setState и функция, возвращаемая useState, принимает два типа аргументов:

  1. Вы можете установить значение непосредственно для него.
  2. Вы можете передать ему функцию, которую они вызовут с предыдущим состоянием в качестве аргумента.

В версии функции вы импортировали функцию Split и использовали ее в:

setSplit(Split);

Обратите внимание, что Split здесь - это функция, и что применимо, это вторая версия setState. Это вызвало бы функцию непосредственно вместо того, чтобы сохранить функцию как компонент. Если компонент вызывается с помощью (), тип <Split /> недопустим (поскольку React больше не может вызывать его, это не функция)

Чтобы обойти это, вы можете сохранить Split какобъект, как в случае с компонентом класса.

const [split, setSplit] = useState(null);
const handleClick = () => {
  import("./Split").then(({ default: Split }) => {
    setSplit({ Split });
  });
};
const Split = split ? split.Split : null;

Теперь setSplit видит объект в качестве аргумента и устанавливает его напрямую.

Codesandbox

2 голосов
/ 30 октября 2019

Мне кажется, я решил вашу проблему не так, как другие ответы. Как сказал Boy With Silver Wings, «вы можете передать ему функцию, которую они вызовут с предыдущим состоянием в качестве аргумента». Чтобы обойти это, нужно написать вызов функции в обновлении и ничего не делать с предыдущим состоянием. ie () => SplitMe

Таким образом, скорректированный код будет просто установленSplit (() => SplitMe)

Посмотрите на изолированную программную среду кода здесь https://codesandbox.io/s/code-splitting-2-0i4v3?fontsize=14

1 голос
/ 30 октября 2019

State может хранить только Strings или Objects, и между классом и ловушкой нет различий, так что это происходит из того, как вы реализовали свою ловушку.

На основе компонентов вы выполняете:

state = {
    Split: null
};

this.setState({ Split })

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

Чтобы все заработало, просто сохраните его так:

import React, { useState } from "react";

const App = () => {
  const [splits, setSplits] = useState({});
  const handleClick = () => {
    import("./Split").then(({ default: SplitMe }) => {
      // console.log(SplitMe);
      setSplits({ SplitMe });
    });
  };

  const { SplitMe } = splits;
  return (
    <div>
      <button onClick={handleClick}>Click Me</button>
      {SplitMe && <SplitMe />}
    </div>
  );
};

export default App;

...