Как заменить useEffect на componentDidMount, если мы вызываем функцию обратного вызова внутри componentDidMount?

с помощью useEffect моя переменная состояния массива не добавляла предыдущее значение, но componentDidMount сделал

Я console.log выхожу из сообщения при использовании useEffect, и все сообщение было правильно распечатано, но состояние не было сохранено, если я установил переменную состояния сообщений как зависимость useEffect, она перейдет в бесконечный цикл

// with useEffect hook
function App() {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    const chatManager = new ChatManager({
      instanceLocator: instanceLocator,
      userId: 'Henry',
      tokenProvider: new TokenProvider({
        url: tokenUrl
      })
    });

    chatManager.connect()
      .then(currentUser => {
        currentUser.subscribeToRoomMultipart({
          roomId: '7b7a1d23-e869-4c19-8eab-e88d5144dd72',
          hooks: {
            onMessage: message => {
             console.log([...messages]);
              setMessages([...messages, message]);
            }
          }
        })
      }).catch(err => {
        console.log('Error on connection', err)
      })
  }, [])

  return (
    <div className="app">
      <RoomList />
      <MessageList messages={messages}/>
      <SendMessageForm />
      <NewRoomForm />
    </div>
  );
}

export default App;

// with componentDidMount
class App extends React.Component {

  constructor() {
    super()
    this.state = {
      messages: []
    }
  }

  componentDidMount() {
    const chatManager = new ChatManager({
      instanceLocator,
      userId: 'Henry',
      tokenProvider: new TokenProvider({
        url: tokenUrl
      })
    })

    chatManager.connect()
      .then(currentUser => {
        currentUser.subscribeToRoomMultipart({
          roomId: '7b7a1d23-e869-4c19-8eab-e88d5144dd72',
          hooks: {
            onMessage: message => {
              this.setState({
                messages: [...this.state.messages, message]
              })
            }
          }
        })
      })
  }

  render() {
    return (
      <div className="app">
        <RoomList />
        <MessageList messages={this.state.messages} />
        <SendMessageForm />
        <NewRoomForm />
      </div>
    );
  }
}

export default App

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


person impressiveHen    schedule 15.10.2019    source источник
comment
Похоже, ваш компонент сбрасывает состояние между рендерами.   -  person Dov Rine    schedule 16.10.2019


Ответы (1)


Поскольку ваше состояние зависит от текущего значения состояния, вам необходимо использовать функциональную форму setMessages. Это означает, что вам не нужно включать messages в качестве зависимости (потому что на самом деле это не будет зависимостью):

  useEffect(() => {
    ...

    chatManager.connect()
      .then(currentUser => {
        currentUser.subscribeToRoomMultipart({
          roomId: '7b7a1d23-e869-4c19-8eab-e88d5144dd72',
          hooks: {
            onMessage: message => {
              setMessages(prevMessages => [...prevMessages, message]);
            }
          }
        })
      })
  }, [])

Дополнительную информацию см. В документации React: https://reactjs.org/docs/hooks-reference.html#functional-updates

person helloitsjoe    schedule 16.10.2019