Redux, localStorage и React: ошибка при обновлении моей страницы - PullRequest
0 голосов
/ 10 января 2020

Моя цель состоит в том, чтобы мое Реактивное состояние сохранялось через refre sh. Я видел, как это делается в учебнике (просто кликните там, если хотите) с помощью браузера localStorage. Я хочу использовать это решение, потому что оно выглядит простым для меня по сравнению с уничтожением Redux Persist.

Ожидаемый результат - страница, которая обновляется и перезагружается, как это было раньше. Вместо этого я получаю ошибку. Я подозреваю, что ошибка происходит, потому что состояние Redux выгружается (?), Затем мой код пытается указать const threadTitle на состояние в this.props.posts[number], которого, конечно, нет, потому что обновление только что выгружено.

Я получаю сообщение об ошибке:

TypeError: Cannot read property 'title' of undefined
fullThread.render
C:/Users/Roland/React_apps/reddit-knockoff/src/FullThread/FullThread.js:30
  27 | 
  28 |  // deliberate exclusion of 2nd parameter in .slice() to make it go til the end
  29 |  const number = this.props.location.pathname.slice(1);
> 30 |  const threadTitle = this.props.posts[number].title;
     | ^  31 |  let flair = null;
  32 |  const upVotes = this.props.posts[number].upvotes;
  33 |  const author = this.props.posts[number].author;

До сих пор я пробовал смотреть обучающие видеоролики и просматривать результаты Google StackOverflow для подсказок о том, как использовать localStorage для решения проблемы. У меня есть некоторый код и работает, но этого недостаточно. Посмотрите:

FullThread. js, где указывается сообщение об ошибке.

import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";

class fullThread extends Component {
    constructor(props) {
        super(props);
        const stateFromStorage = localStorage.getItem("state");
        if (this.props.posts === null) {
            this.props.returnPostsToState(stateFromStorage);
        }
    }

    componentDidMount() {

        localStorage.setItem("state", this.props.posts);
    }

    render() {

        // deliberate exclusion of 2nd parameter in .slice() to make it go til the end
        const number = this.props.location.pathname.slice(1);
        const threadTitle = this.props.posts[number].title;
        const upVotes = this.props.posts[number].upvotes;
        const author = this.props.posts[number].author;
        const age = this.props.posts[number].age;
        const postText = this.props.posts[number].postText;


        return (
            <div>
                <div className="MainBody">
                    <h4>Thread titled: {threadTitle}</h4>
                    <p>Removed content. The constants threadTitle, upVotes, author, age and postText go here</p>

                </div>
            </div>
        );
    }
}

const mapDispatchToProps = dispatch => {
    return {
        returnPostsToState: stateFromStorage =>
            dispatch({ type: "RETURN", payload: stateFromStorage })
    };
};

const mapStateToProps = state => {
    return {
        posts: state.posts
    };
};

export default connect(mapStateToProps, mapDispatchToProps)(fullThread);

posts. js, в котором содержится мой редуктор

const initialPosts = {
    posts: [
        {
            id: 0,
            upvotes: 831,
            flair: null,
            title: "New? READ ME FIRST!",
            author: "michael0x2a",
            age: "2 years",
            comments: 15,
            postText:
                "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
        }
    ],
    loggedIn: false
};

const reducer = (state = initialPosts, action) => {
    if (action.type === "ADD_POST") {
        console.log("HEY: ", action.newPost);
        console.log(state.posts.concat(action.newPost.post.tempThread));
        return {
            ...state,
            // receives newPost data from app.js
            posts: state.posts.concat(action.newPost.post.tempThread)
        };
    }
    if (action.type === "RETURN") {
        console.log("RETURNED! ", action.payload);
        console.log("RETURNED: ", state.posts);
        return {
            ...state,
            posts: state.posts.concat(action.payload)
        };
    }

    return state;
};

export default reducer;

Я бы опубликовал приложение. js, но я не думаю, что это актуально.

Мое несогласие с моим кодом и ошибкой в ​​том, что, я думаю, мой код должен работать! Сначала я вызываю localStorage.setItem("state", this.props.posts); в моем методе componentDidMount (), чтобы настроить свой localStorage с содержимым переменной состояния моих сообщений. Затем, когда страница перезагружается, мой метод конструктора - который запускается первым, перед любым другим кодом в жизненном цикле компонента !!! - вызывает this.props.returnPostsToState(stateFromStorage);, тем самым сбрасывая глобальное состояние Redux с содержимым «state From Storage», которое является моим исходным содержимым сообщений!

Что я делаю не так?

Я понимаю Не знаю, как это реализовать, но, думаю, есть какое-то рабочее решение, в котором я go, "if (stateHasReloaded) { const threadTitle = this.props.posts[number].title; }" я просто пока точно не знаю, как это выглядит.

Заранее спасибо за любую помощь

1 Ответ

1 голос
/ 10 января 2020

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

 if (this.props.posts === null) {
      this.props.returnPostsToState(JSON.parse(stateFromStorage));
 }

А также, когда вы сохраняете в localalstorage, упорядочьте ваши данные следующим образом:

componentDidMount() {

    localStorage.setItem("state", JSON.stringify(this.props.posts));
}

И для более безопасной стороны вы всегда можете проверить, есть ли данные или нет, потому что вы получаете номер из URL, чтобы кто-нибудь изменил это номер, который не имеет сообщений:

const threadTitle = this.props.posts[number]?this.props.posts[number].title:'';

Позвольте мне, если он работает или нет, увидим.

...