Использование эффекта не позволяет сохранять данные в локальном хранилище

#reactjs #local-storage #use-effect

Вопрос:

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

Это мой компонент:

 export const WorkChat = (props) => {
    const [messageValue, setMessageValue] = useState('');
    const [edit, setEdit] = useState(null);
    const [editmessageValue, setMessageEditValue] = useState('')

    const submitMessage = () => {
        const newMessage = {
            id: Math.floor(Math.random() * 10000),
            message: messageValue
        }
        props.addMessage(newMessage);
        setMessageValue('')
    }

    const removeMsg = (id) => {
        props.deleteMessage(id)
    }

    const goToEditMode = (message) => {
        setEdit(message.id);
        setMessageEditValue(message.message)
    }

    const saveChanges = (id) => {
        const newMessagesArray = props.messages.map(m => {
            if(m.id === id){
                m.message = editmessageValue
            }
            return m
        })
        props.updateMessage(newMessagesArray);
        setEdit(null)
    }

    
    useEffect(()=> {
        let data = localStorage.getItem('work-messages');
        if(data){
          props.setMessages(JSON.parse(data))
        }
      }, []);

      
    useEffect(()=> {
        localStorage.setItem('work-messages', JSON.stringify(props.messages))
    },[props.messages])


    return (
        <div className={s.workChatContainer}>
           <input className={s.workInput} placeholder='Enter work message...' onChange={(e)=> setMessageValue(e.target.value)} value={messageValue}/>
           <button className={`${s.btn} ${s.sendBtn}`} onClick={()=>submitMessage()}><SendIcon style={{fontSize: 20}}/></button>
           <div>
                {props.messages.map(m => (
                    <div key={m.id} className={s.messages}>
                        {edit !== m.id ? <div>
                            <span className={s.message}>{m.message}</span>
                            <button className={`${s.btn} ${s.deleteBtn}`} onClick={()=> removeMsg(m.id)}><DeleteOutlineIcon style={{fontSize: 15}}/></button>
                            <button className={`${s.btn} ${s.editBtn}`} onClick={()=> goToEditMode(m)}><EditIcon style={{fontSize: 15}}/></button>
                        </div>
                        :
                        <form>
                            <input className={s.editInput} value={editmessageValue} onChange={(e)=> setMessageEditValue(e.target.value)}/>
                            <button className={`${s.btn} ${s.saveBtn}`} onClick={()=> saveChanges(m.id)}><BeenhereIcon style={{fontSize: 15}}/></button>
                        </form>
                    }
                        
               </div>
                ))} 
           </div>
        </div>
    )
}
 

На всякий случай, это мой контейнерный компонент:

 import { connect } from "react-redux"
import { setFloodMessagesAC, addFloodMessageAC, deleteFloodMessageAC, upadateMessageAC } from "../../redux/flood-reducer"
import { FloodChat } from "./FloodChat"
import { useEffect } from 'react'
import  data  from '../../StaticState/dataForFlood.json'


const FloodChatApiContainer = (props) => {

    useEffect(()=> {
        props.setFloodMessages(data)
    }, [])
    
    
    return <FloodChat messages={props.messages}
                      setFloodMessages={props.setFloodMessages}
                      addFloodMessage={props.addFloodMessage}
                      deleteFloodMessage={props.deleteFloodMessage}
                      upadateMessage={props.upadateMessage}
                                                    />
}

const mapStateToProps = (state) => ({
    messages: state.flood.messages
})

export const FloodChatContainer = connect(mapStateToProps, {
    setFloodMessages: setFloodMessagesAC,
    addFloodMessage: addFloodMessageAC,
    deleteFloodMessage: deleteFloodMessageAC,
    upadateMessage: upadateMessageAC
})(FloodChatApiContainer)
 

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

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

1. Срабатывает ли ваша вторая useEffect() кнопка при props.messages изменении?

2. @Ryan Le да, он срабатывает, просто проверил его через console.log, он срабатывает в любой момент, когда я что-то меняю(удаляю, добавляю или редактирую)

Ответ №1:

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

 const FloodChatApiContainer = (props) => {

    useEffect(()=> {
        props.setFloodMessages(data)
    }, [])
            
    useEffect(()=> {
        let data = JSON.parse(localStorage.getItem('flood-messages'));
        if(data){
            props.setFloodMessages(data)
        }
        console.log('get')
    }, [])

    useEffect(() => {
        localStorage.setItem('flood-messages', JSON.stringify(props.messages));
        console.log('set')
      }, [props.messages]);

    
    
    return <FloodChat messages={props.messages}
                      setFloodMessages={props.setFloodMessages}
                      addFloodMessage={props.addFloodMessage}
                      deleteFloodMessage={props.deleteFloodMessage}
                      upadateMessage={props.upadateMessage}
                                                    />
}

const mapStateToProps = (state) => ({
    messages: state.flood.messages
})

export const FloodChatContainer = connect(mapStateToProps, {
    setFloodMessages: setFloodMessagesAC,
    addFloodMessage: addFloodMessageAC,
    deleteFloodMessage: deleteFloodMessageAC,
    upadateMessage: upadateMessageAC
})(FloodChatApiContainer)