在页面刷新或更改时保存通过Redux传递的数据的问题

时间:2017-07-18 01:27:29

标签: javascript html reactjs redux react-redux

每当此项目选择添加到购物车时,我都会尝试保存用户的项目选择。每当用户按下添加到特定项目的购物车时,我都会使用Redux传递商品数据。在我的Cart组件中,我可以查看添加到购物车的最后一项的项目选择数据。此用户选择项数据类似于Object {price: 25, item: "Hoodie", size: "medium"}。我希望能够在我的Cart组件中存储添加到购物车的每个选项。这是Cart

import React, { Component } from 'react';
import {addCart} from './Shop'; 
import { connect } from 'react-redux';

export class Cart extends Component {
    constructor(props) {
        super(props);
        this.state = {items: this.props.cart,cart: [],total: 0};
    }

    itemBucket(item) {
        this.state.cart.push(this.state.items);
        this.countTotal();
    }

    countTotal() {
        var total = 0;
        console.log(this.state.cart);
        this.state.cart.forEach(function(item, index){
            total = total + item.price;
            console.log (total);
        })
    }

    componentDidMount () {
        window.scrollTo(0, 0);
        this.itemBucket();
    }

    render() {
        return(
            <div className= "Webcart" id="Webcart">
                <addCart cartItem={this.props.cart} />
            </div>
        );
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        onCartAdd: (cart) => {
            dispatch(addCart(cart));
        },
    }
}

function mapStateToProps(state) {
  return { cart: state.cart };
}

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

我已将itemBucket()设置为将每个项目选择添加到state中的购物车数组中的功能。但是这不起作用,只传递添加到购物车的最后一项。这可能与改变我的Redux Store的工作方式有关,但我真的不知道如何应用它。这是我的Redux商店:

import { createStore, applyMiddleware } from 'redux';
import  reducer  from './reducers';
import thunkMiddleware from 'redux-thunk';
import {createLogger} from 'redux-logger';


const store = createStore(
  reducer,
  applyMiddleware(
    createLogger(),
    thunkMiddleware
  )
);
export default store; 

即使刷新或更改页面,如何保存传递给Cart的每个项目?

修改

这是我的reducer组件:

import {ADD_CART} from './actions';

export default Reducer;

var initialState = {
  cart:{},
  data: [],
  url: "/api/comments",
  pollInterval: 2000
};

function Reducer(state = initialState, action){
    switch(action.type){
        case ADD_CART:
            return {
                ...state,
                cart: action.payload
            }

            default:
                return state 
    };
}

3 个答案:

答案 0 :(得分:2)

目前,您的应用中发生的事情是,每次刷新页面时,redux存储都会初始化并使用reducer提供的默认值。

您可以通过将对象作为createStore的第二个参数来覆盖这些默认值。

const store = createStore(
    reducer, // default values provided by reducers
    {key: "value"}, // overwrites matching key/val pairs, think Object.assign with the first reducer argument
    applyMiddleware(createLogger(), thunkMiddleware)
)

此示例使用浏览器的localStorage来存储和检索数据。

localStorage.js文件使用redux状态作为要存储在localStorage中的数据。

localStorage.js

export const loadState = () => {
    try {
        let serializedState = localStorage.getItem('state')

        if (serializedState === null) {
            return undefined
        }
        let storageState = JSON.parse(serializedState)

        return storageState
    } catch (err) {
        return undefined
    }
}

export const saveState = (state) => {
    try {
        const serializedState = JSON.stringify(state)
        // saves state to localStorage
        localStorage.setItem('state', serializedState)
    } catch (err) {
        console.log('error and unable to save state', err)
    }
}

现在你可以配置redux存储了,所以当它初始化时,会检索localStorage中的'state'项,并覆盖默认的reducer值。

saveState函数将持续你的redux状态。它通过使用store.subscribe()监听redux商店中的更改来实现此目的。进行更改时,系统会调用saveState

安装lodash以启用限制,否则saveState将被调用太多次。

<强> configureStore.js

import { createStore, applyMiddleware } from 'redux'
import  reducer  from './reducers';
import thunkMiddleware from 'redux-thunk'
import createLogger from 'redux-logger'
import { loadState, saveState } from './localStorage'
import throttle from 'lodash/throttle'

let middlewares = [createLogger(), thunkMiddleware]

const configureStore = () => {
    const localStorageState = loadState()

    const store = createStore(
        reducer,
        localStorageState,
        applyMiddleware(...middlewares)
    )

    // everytime the state changes, it will be saved to 
    store.subscribe(throttle(() => {
        saveState(store.getState())
    }, 1000))

    return store
}
export default configureStore

现在按以下方式创建商店。

<强> index.js

import configureStore from './configureStore'

const store = configureStore()

此实现演示了如何直接与localStorage交互,并从Dan那里获取了这个想法。您可以稍后优化此存储和检索过程。目前,只要在商店中发生更改,整个redux状态就会写入localStorage。

一旦您更接近为redux商店建立数据结构,您可以慢慢分解状态树并将它们设置为localStorage中的单个项目。 (一种可能的解决方案)

然后订阅/收听特定的状态树而不是整个商店,并在发生更改时保存它们。

store.getState().some.data.set代替store.getState()

另外,检查npm,有些人已经创建了一些很酷的方法来解决这个问题。

答案 1 :(得分:2)

我的建议是使用redux-persist将购物车状态保存到localStorage。与编写自己的实现相比,它会更容易,并且有一个活跃的社区(所以如果你遇到任何问题/错误,你可能不会是唯一的问题/错误。)

Redux商店

import { createStore, applyMiddleware, compose } from 'redux';
import { persistStore, autoRehydrate } from 'redux-persist';
import reducer from './reducers';
import thunkMiddleware from 'redux-thunk';
import { createLogger } from 'redux-logger';

const store = createStore(
  reducer,
  undefined,
  compose(
    applyMiddleware(createLogger(), thunkMiddleware),
    autoRehydrate()
  )
);

persistStore(store, { whitelist: ['cart'] });

export default store; 

<强>减速

import { ADD_CART } from './actions';
import { REHYDRATE } from 'redux-persist/constants';

export default Reducer;

var initialState = {
  cart:{},
  data: [],
  url: "/api/comments",
  pollInterval: 2000
};

function Reducer(state = initialState, action){
  switch(action.type){
    case REHYDRATE:
      if (action.payload && action.payload.cart) {
        return { ...state, ...action.payload.cart };
      }
      return state;

    case ADD_CART:
      return {
        ...state,
        cart: action.payload
      }

      default:
        return state 
  };
}

请参阅此处的完整文档:https://github.com/rt2zz/redux-persist

答案 2 :(得分:1)

  

我将itemBucket()设置为一个函数,将每个项目选择添加到状态中找到的购物车数组中。但是这不起作用,只传递添加到购物车的最后一项。

使用

 constructor(props) {
    super(props);
    this.state = {cart: this.props.cart,total: 0};
}
 itemBucket(item) {
            this.setState({cart : [...this.state.cart, item]});
        }
    componentDidUpdate(){
      this.countTotal();
    }

countTotal将显示旧购物车,如果放入itemBucket,因为setState不同步。你可以把它放在componentDidUpdate中。

对于刷新之间,通过使用服务调用将邮件存储在服务器上以发布计数,或使用localStorage / sessionStorage / indexedDb将其保留在客户端中。在componentWillMount中,从上面的位置获取此信息,并在客户端上使用它来补充您的redux商店。