1

再生する必要がuseEffect()あるメッセージ サウンドがある場合はトリガー ブール値の状態をチェックし、再生後、そのアクティブなメッセージ トリガーを状態で false に設定します。

ただし、useEffect() は無限ループに入り、アプリがクラッシュします。おそらく、状態を変更すると再びトリガーされるためです(そして再び...)

通常、useState を使用すると、次のような方法で簡単に修正できます。useEffect(() => {logic}, [trigger])

私の場合、useState は使用していませんが、リデューサーを使用して状態を変更しています。

Edit: The weird thing is, the reducer sometimes works to modify state, and sometimes it does not. It will execute without errors but the state remains unchanged.

コメントしたコードをお見せしましょう:

import React, { useEffect } from "react";
import { getCachedImage } from "../helpers";

const MessageNotification = (props) => {
  const messageImg= getCachedImage("/ui/newmessage.png");

  

  // Function that plays given sound
  function playSound(soundFile) {
    let audio = new Audio("/audio/messages/" + soundFile);
    audio.play();
  }

  // Check if a Message is set to active. If so, execute logic
  useEffect(() => {
    // Get messages from state and find the message with "active" set to true
    const messagesState = props.state.messages;
    const activeMessage = messagesState.find((element) => element.active === true);

    if (activeMessage) {

      playSound(activeMessage.audio);

      // Mark the message as userNotified and set it to inactive in state
      let updatedMessagesState = messagesState ;
      let index = messagesState.indexOf(activeMessage);

      if (~index) {
        updatedMessagesState[index].userNotified= true;
        updatedMessagesState[index].active = false;
      }

      /* This is the weird part, the updatedMessagesState is correct, 
but the dispatch reducer does not pass it to state. 
This does work when I remove the useEffect 
(but that gives me a fat red warning in console) */

      props.dispatch({ type: "UPDATE_MESSAGES", payload: updatedMessagesState });
    }
  });

  return (
    <div>
      <img src={"images" + messageImg} alt="message" width="90" height="90"></img>
    </div>
  );
};

export default MessageNotification;

ご覧のとおり、useState は使用しませんが、代わりにレデューサーを使用します。次のようなものに関連することがよくある解決策は、私が知る限り、私の解決策ではありません。

// Not applicable solution for me, since I use reducer
const [trigger] = useState();

useEffect(() => {
    // Logic here
}, [trigger]);

編集: useEffect で使用された場合、リデューサーは状態を変更しないように見えるため、そのコードを投稿させてください。

const reducer = (state, action) => {
  switch (action.type) {
    case "UPDATE_MESSAGES":
      return { ...state, messages: action.payload };
    default:
      throw new Error();
  }
};

export default reducer;
4

3 に答える 3