Эффект использования не выполняется при изменении prop

#reactjs #react-hooks #react-props #use-effect

#reactjs #реагирующие хуки #реагировать-реквизит #использование-эффект

Вопрос:

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

Я ожидал, что при обновлении экземпляра класса это вызовет useEffect, потому что prop был изменен, но этого не происходит.

есть идеи, почему? это потому, что я отправляю класс как реквизит, а не атрибуты класса?

SqlSchema.jsx

 //this component should update the "connectionParams" class property
const SqlSchema = ({ sqlConnection }) => {
    const [activeStep, setActiveStep] = useState(0);
    //useEffect isn't triggered after executing "setConnection"
    useEffect(() => console.log(sqlConnection.connectionParams), [sqlConnection.connectionParams]);

    const setConnection = (params) => {
      sqlConnection.setConnection(params);
    };
    
    const stepContent = [
      <ConnectToDB data={sqlConnection.connectionParams} onChange={setConnection} />,
    ];
    
    return (
      <div className="sql-schema">
          <Typography>{stepContent[activeStep]}</Typography>
      </div>
    );
  };
 

Router.jsx

 //here I'm passing the class to the component
<Route path="/create-from-sql"><SqlSchema sqlConnection={SqlConnection} /></Route>
 

SqlConnection.js

 class SqlConnection {
    connectionParams = {};

    setConnection(params) {  
        this.connectionParams = params;
    }
}

export default new SqlConnection();
 

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

1. вы отправляете новое соединение каждый раз при обновлении, действительно ли это то поведение, которое вы хотите? Он не вызывается, потому что параметры не изменены.

Ответ №1:

Обновление: почему вы не сохраняете connectionParams в a useState ? Таким образом, вы можете правильно передать их и выполнить повторный запуск.

 const [connectionParams, setConnectionParams] = useState({});

return <SqlSchema connectionParams={connectionParams} setConnectionParams={setConnectionParams} />
 

Вы создаете новое соединение для каждого рендеринга родительского sqlConnection={new SqlConnection()} элемента .
Попробуйте создать соединение при монтировании, а затем передать переменную дочернему элементу.

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

1. Как SqlSchema будет известно, что параметры изменились и должны быть повторно отображены?

2. поскольку реквизит SqlConnection изменился @kinduser

3. Но изменение объекта ref не запускает повторный рендеринг.

4. У меня много логики, которую нужно выполнить в классе (я помещаю здесь только соответствующий код) в отношении подключения к sql, и создание в классе помогло бы мне избежать повторяющихся действий и итераций, сохраняя промежуточные результаты на каждом шаге в sqlSchema

5. У вас может быть логика для подключения к sql в отдельных функциях, и если необходимы параметры подключения, вы можете передать их в любую функцию подключения к sql. Но наличие реквизита в состоянии — лучший способ управлять повторным использованием дочернего компонента. Вы также можете передать состояние объекту с помощью new SqlConnection(conParams);

Ответ №2:

Передача SqlConnection не вызовет обновление компонента при connectionParams обновлении внутри класса. Вам нужно будет каким-то образом подписаться на connectionParams изменения. Приведенный ниже пример передает задатчик состояния SqlConnection классу, поэтому, когда параметры обновляются, запускается изменение состояния, useEffect теперь он может прослушивать params изменения, и теперь вы можете использовать их и устанавливать sql-соединение с соответствующими параметрами.

 class SqlConnection {
  stateSetter;
  
  constructor(setter) {
    this.stateSetter = setter;
  }
  
  connectionParams = {};

  setConnection(params) {  
    this.connectionParams = params;
    this.stateSetter(this.connectionParams);
  }
}

const SqlSchema = () => {
  const [value, setValue] = React.useState({});
  const ref = React.useRef(null);
  
  React.useEffect(() => {
    ref.current = new SqlConnection(setValue);
  }, []);
  
  React.useEffect(() => {
     console.log('Current params - ', value); // do stuff with params
  }, [value]);

  const setParams = () => {
    ref.current.setConnection({ foo: 'bar' });
  };

  return <div>
    <button onClick={setParams}>Update params</button>
    {JSON.stringify(value)}
  </div>
}

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

<div id="root"></div>