Я настроил Redux в своем приложении React, однако я не получаю никаких данных, когда использую this.props для доступа к данным в другом компоненте в отдельном файле. Мое действие выполняется, и он передает данные, которые я хочу. Это мой actions.js:

export const ADD_CART = 'ADD_CART';

export function addCart(item){
    return {
        type: ADD_CART,
        payload: item
    }
};

Мой reducer.js это:

import {ADD_CART} from './actions';

export default Reducer;

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

Мой создатель действий содержит cart, который я хочу передать компоненту:

...
class WebShop extends Component {
    ...

    handleClick() {
        let cart = {price:0,item:"userselection",size:this.state.value};
        this.props.onCartAdd(cart);
    } 

   ...


    render() {
        return (
            ..
}

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

function mapStateToProps(state) {
   return {
      cartItem: state.reducer,
   }
}

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

Когда я пытаюсь получить доступ к cart в другом файле и компоненте так:

import React, { Component } from 'react';
import { connect } from 'react-redux';

export default class Cart extends Component {
    render() {
        console.log(this.props.cart);
        return(
            <div className= "Webcart" id="Webcart"></div>
        );
    }
}

Это мой store.js:

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


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

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

Мой Provider находится в моем app.js файле:

import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, IndexRoute, hashHistory } from 'react-router';
import {Provider} from 'react-redux';
import store from '../store';

import App from 'views/App';
import Home from 'views/Home';
import About from 'views/About';
import Cart from 'views/webcart';


console.log(store);
ReactDOM.render(
    <Provider store={store}>
        <Router history={ hashHistory }>
            <Route path='/' component={ App }>
                <IndexRoute component={ Home } />
                <Route path='about' component={ About } />
                <Route path='Cart' component={ Cart } />
            </Route>
        </Router>
    </Provider>,    
    document.getElementById('app') // eslint-disable-line
);

После обновления моего кода для использования mapStateToProps теперь я получаю ошибку Uncaught TypeError: Cannot read property 'Reducer' of undefined. Почему я получаю это, если API должен получить доступ к Редуктору?

2
feners 29 Май 2017 в 04:25

2 ответа

Для доступа к данным вам нужно передать состояние в API подключения. Вы только перешли в диспетчерское действие на реквизит

function mapStateToProps(state) {
  return {
    SomeDataProperty: state.Reducer
  }
}

Кроме того, ваш mapDispatchToProps находится в операторе возврата вашего компонента, лучше поместить эту функцию в другой файл (контейнер), а затем указать этот контейнер с подключенными реквизитами на компонент WebShop, если вы пытаетесь сделать так, чтобы WebShop передавал реквизиты в корзину компонент.

Примере:

WebshopContainer.jsx (контейнерный компонент, который будет передавать реквизиты компоненту)

import WebShop from './WebShop';

function mapStateToProps(state) {
  return {
    SomeDataProperty: state.Reducer // prop Reducer was taken from your reducer.js because it was passed into here from the connect API
  }
}

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

export default connect(mapStateToProps, mapDispatchToProps)( WebShop ); // pass in the component here 

Файл компонента, содержащий компонент WebShop, и вы хотите передать реквизиты компоненту, чтобы компонент мог получить доступ к реквизитам:

class WebShop extends Component {
  constructor(props) {
    super(props);
    this.state = {
      cartData: {}
    }
  }
  componentWillReceiveProps() {
    const waitForProps = setInterval(() => {
      if (this.props.Reducer.hasOwnProperty('some prop you gave it')) {
        clearInterval(waitForProps);
        this.setState({ cartData: this.props.Reducer['some data property you used'] });
      }
    });
  }
  handleClick() {
      let cart = {price:0,item:"userselection",size:this.state.value};
      this.props.onCartAdd(cart);
  }
  render() {
    return (
      <div>
        <Cart cart={ this.state.cartData }
      </div>
    );
  }
}
1
Chris 29 Май 2017 в 01:49

Переместите ваше начальное состояние из store.js в ваше reducer.js и передайте его функции-редуктору, чтобы установить состояние по умолчанию, например:

const initialState = { 
  cart: {}, // change this to object to hold that cart your're 
           //passing or an array to hold multiple cart, in which 
           // case you will need to handle the return of your
           // state differently in your reducer
  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;
}

Это гарантирует, что у вас нет неопределенных состояний, а действие, не зарегистрированное в reducer, возвращает состояние хранилища.

Ваше действие отправляет полезную нагрузку item, которая устанавливается как state.cart хранилища, а не state.reducer.

Так что в вашем WebShop component измените свой mapStateToProps

function mapStateToProps(state) {
   return {
      cartItem: state.cart.item // to access your item inside your cart
   }
}

И чтобы получить доступ к cart в другом компоненте, вам нужно либо передать его реквизиту этого компонента, как это для компонентов без состояния const cartItem = this.state.cartItem // получить это из состояния или реквизита или из mapDispatchToProps в connect, как вы делаете в webshop component

<Component cart={cartItem} />

Так как cartItem теперь в вашем состоянии, вы должны быть в состоянии сделать что-то подобное.

class OtherComponent extends Component {
  render() {
    return (
     <div>
       {/* render some other components */}
       <Component cartItem={this.props.cartItem}
     </div>
  }
}
function mapStateToProps(state) {
  return { cartItem: state.cart.item };
}
export default connect(mapStateToProps, null)(OtherComponent);

Надеюсь, это прояснит вашу проблему.

1
Faaiz Khan 4 Июн 2017 в 19:16