Calling action with Redux-thunk not working - javascript

I am trying to use redux with react to do an api call to GET some data. When calling the function in my component, the reducer is not seeing the action.type and the function is returning a Promise resolved. I've not used redux-thunk before. The code as I have I feel should work but I am having difficulty finding the error. Here is the code.
Index.js
const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(thunkMiddleware, devToolsEnhancer)));
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('root')
);
Action
import axios from 'axios';
export const GET_ALL_CASES = "GET_ALL_CASES";
const getCasesSuccess = (cases) => {
return {
type: GET_ALL_CASES,
cases
}
};
export const getAllCases = () => {
return (dispatch) => {
axios.get('https://corona.lmao.ninja/countries?sort=country')
.then(response => {
dispatch(getCasesSuccess(response.cases))
})
.catch(error => {
throw(error)
})
}
}
Reducer
import { GET_ALL_CASES } from '../actions';
const initialState = {
allCases: []
}
const rootReducer = (state = initialState, action) => {
switch (action.type) {
case GET_ALL_CASES:
return { ...state, allCases: [...action.cases]}
default:
return state;
}
}
export default rootReducer;
Component
class Second extends React.Component {
constructor(props) {
super(props);
this.state = { }
}
componentDidMount = () => {
getAllCases()
}
render() {
return (
<div>
{this.props.data[0]}
</div>
);
}
}
const mapStateToProps = (state) => (
{
data: state.allCases
}
)
const mapDispatchToProps = dispatch => {
return {
getAllCases: () => dispatch(getAllCases())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Second);
When calling the function, if I change it to this.props.getAllCases(), I get this error.
Unhandled Rejection (Error): Expected the reducer to be a function.
▶ 5 stack frames were collapsed.
getAllCases
C:/Users/Owner/Desktop/corona-app/src/containers/second.js:33
30 |
31 | const mapDispatchToProps = dispatch => {
32 | return {
> 33 | getAllCases: () => dispatch(getAllCases())
| ^ 34 | }
35 | }
36 |

There are different ways to use dipatchMapToProps or how ever its named.
But don't think too much on it as I do, use the easiest one
as an object
const dispatchToProps = {
fun1,
enter,
code,
herefun2
}
as function
const mapDispatchToProps = dispatch => {
return {
// dispatching plain actions
increment: () => dispatch({ type: 'INCREMENT' }),
decrement: () => dispatch({ type: 'DECREMENT' }),
reset: () => dispatch({ type: 'RESET' })
}
import React from "react";
import {connect} from "react-redux";
import {getAllCases} from "path-of-the-file";
class Second extends React.Component {
constructor(props) {
super(props);
this.state = {
someState: ""
}
}
componentDidMount () {
const { getAllCases } this.props;
getAllCases()
}
render() {
const {data} = this.props;
return (
<div>
{data[0]}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
data: state.allCases
}
}
const mapDispatchToProps = { getAllCases }
export default connect(mapStateToProps, mapDispatchToProps)(Second);
```

Related

How to set loader for a promise.all action in React Redux?

So when I check Redux dev-tools i see that I've received my data and they are a part of the state, but when I try to use conditional rendering it wont render the page and gives error TypeError: Cannot read property 'Global Quote' of undefined !
If I just use this.props.data.TSLA it works fine and the page renders...
When I use this.props.data.TSLA["Global Quote"]["01. symbol"] page won't render! (the keys are strings in the JSON so I need to use square brackets).
I am also using Redux-Thunk !
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { START_FETCH_DATA } from './redux/dataReducer';
class Fetcher extends Component {
componentDidMount() {
this.props.START_FETCH_DATA()
}
render() {
const { data, dataLoading } = this.props;
return (
<li className="tesla-container">
{ this.props.dataLoading ?
(<div className="ticker"> Loading! </div>)
:
(<div className="ticker">{
this.props.data.TSLA["Global Quote"]["01. symbol"] }</div>) }
</li>
)
}
const mapStateToProps = (state) => {
return {
data: state.data,
dataLoading: state.dataLoading
}
}
const mapDispatchToProps = (dispatch) => {
return {
START_FETCH_DATA: bindActionCreators(START_FETCH_DATA, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Fetcher)
and here is the reducer + actions...
export const dataReducer = (state = {dataLoading: true}, action) => {
switch(action.type) {
case "START_FETCH_DATA":
return {...state, dataLoading: true}
case "FINISH_FETCH_DATA":
return {...state, dataLoading: false, data: action.payload}
default:
return state;
}};
export const START_FETCH_DATA = () => {
return (dispatch) => {
Promise.all(
[
fetch(`https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=TSLA&apikey=LOL`).then(data => data.json()),
fetch(`https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=AMZN&apikey=LOL`).then(data => data.json())
]
)
.then(([TSLA, AMZN]) => {
dispatch({ type: "FINISH_FETCH_DATA", payload: {TSLA, AMZN} })
})
}};
DEVTOOLS SCREENSHOT
https://imgur.com/a/2Tcrdpe
For starters, you should use the data provided by redux in render():
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { START_FETCH_DATA, dataReducer } from './redux/dataReducer';
class Fetcher extends Component {
componentDidMount() {
this.props.START_FETCH_DATA()
}
render() {
return (
<li className="tesla-container">
{ this.props.dataLoading ?
(<div className="ticker"> Loading! </div>)
:
(<div className="ticker">{
this.props.data.TSLA["Global Quote"]["01. symbol"] }</div>) }
</li>
)
}
const mapStateToProps = (state) => {
return {
data: state.data,
dataLoading: state.dataLoading
}
}
const mapDispatchToProps = (dispatch) => {
return {
START_FETCH_DATA: bindActionCreators(START_FETCH_DATA, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Fetcher)
I fixed my issue.
Fixed code below:
`const mapStateToProps = (state) => {
return {
dataLoading: state.dataReducer.dataLoading,
data: state.dataReducer.data
}
}`
instead of
`const mapStateToProps = (state) => {
return {
dataLoading: state.dataLoading,
data: state.data
}
}`

Updating redux state onClick

I have a component that displays data from the state. I'm using redux for state. I want to be able to click a button and filter the state. But I'm stuck on dispatching the action from the button.
Right now I have a button that is supposed to dispatch the action but it's not being called. I'm not sure if the mapsToDispatchProps is wrong or it's something else.
Here is the actions
import { GET_POLLS, SHOW_APPROVAL } from './types';
const URL = 'https://projects.fivethirtyeight.com/polls/polls.json';
export const getPolls = () => dispatch => {
return fetch(URL)
.then(res => res.json())
.then(polls => {
dispatch({ type: GET_POLLS, payload: polls })
})
}
export const getApproval = () => ({ type: SHOW_APPROVAL })
reducer
import {
GET_POLLS,
SHOW_APPROVAL
} from '../actions/types';
const pollReducer = (state = [], { type, payload }) => {
switch (type) {
case GET_POLLS:
return payload
case SHOW_APPROVAL:
return (payload.type === "trump-approval")
default:
return state
}
}
export default pollReducer;
types
export const GET_POLLS = 'GET_POLLS';
export const POLLS_LOADING = 'POLLS_LOADING';
export const SHOW_ALL = 'SHOW_ALL';
export const SHOW_APPROVAL = 'SHOW_APPROVAL';
list that displays data
import React, { Component } from 'react'
import { PollCard } from '../Components/PollCard'
// import FilterLink from './FilterLink'
import * as moment from 'moment';
import { connect } from 'react-redux'
import { getPolls, getApproval } from '../actions/index';
class PollList extends Component {
componentDidMount() {
this.props.getPolls();
}
render() {
console.log("rendering list")
const { polls } = this.props
const range = 30
var dateRange = moment().subtract(range, 'days').calendar();
var filteredPolls = polls.filter(e => Date.parse(e.endDate) >= Date.parse(dateRange)).reverse()
return (
<React.Fragment>
<button onClick={getApproval}>
Get Approval
</button>
{console.log("get approval", getApproval)}
{
filteredPolls && filteredPolls.map((poll) => (
<div key={poll.id}>
<PollCard poll={poll} />
{/* {(poll.type)} */}
</div>
))
}
</React.Fragment>
)
}
}
const mapStateToProps = state => ({
polls: state.polls
});
const mapDispatchToProps = {
getApproval
};
export default connect(
mapStateToProps,
mapDispatchToProps,
{ getPolls, getApproval }
)(PollList);
// export default PollList;
Your mapDispatchToProps() appears to be configured incorrectly. You need to define a function that returns an object, defining a key-value pair for each action you want to make available as a prop in your component.
const mapDispatchToProps = (dispatch) => {
return {
getApproval: () => {
dispatch(getApproval())
},
getPolls: () => {
dispatch(getPolls())
}
}
}
export default connect(
mapStateToProps,
mapDispatchToProp)(PollList);
Now getPolls is available as prop and you can use it in componentDidMount()
componentDidMount() {
this.props.getPolls();
}
You should also create an onClick handler for your getApproval action
handleClick = () => {
this.props.getApproval()
}
And then connect it to your onClick event-listener
<React.Fragment>
<button onClick={this.handleClick}>
Get Approval
</button>
console.log("get approval", getApproval)}
{
filteredPolls && filteredPolls.map((poll) => (
<div key={poll.id}>
<PollCard poll={poll} />
{/* {(poll.type)} */}
</div>
))
}
</React.Fragment>
Action File
export const getPolls = () => dispatch => {
fetch(URL)
.then(res => res.json())
.then(polls => {
dispatch({ type: GET_POLLS, payload: polls })
})
.catch(errors => {
dispatch({ type: "GET_ERRORS", payload: errors.response.data })
})
}
Reducer
import {
GET_POLLS,
SHOW_APPROVAL
} from '../actions/types';
const pollReducer = (state = [], { type, payload }) => {
switch (type) {
case GET_POLLS:
return payload
case SHOW_APPROVAL:
return state.filter((poll) => {
return poll.type === "trump-approval"
})
case "GET_ERRORS":
return payload
default:
return state
}
}
export default pollReducer;
You are not calling the action function.
// Either destructure it
const { polls, getApproval } = this.props;
<button onClick={getApproval}>
Get Approval
</button>
// Or use this.props.function
<button onClick={this.props.getApproval}>
Get Approval
</button>
// You don't need this
const mapDispatchToProps = {
getApproval
};
// You don't need this
const mapStateToProps = state => {
return {polls: state.polls};
};
export default connect(
mapStateToProps,
// Doing this is easier, cleaner & faster
{ getPolls, getApproval }
)(PollList);
Here you are doing it correctly;
componentDidMount() {
this.props.getPolls();
}

Action doesn't update the store

|I have the following component based on this:
**WarningModal.js**
import React from 'react';
import ReactDOM from 'react-dom';
import {connect, Provider} from 'react-redux';
import PropTypes from 'prop-types';
import {Alert, No} from './pure/Icons/Icons';
import Button from './pure/Button/Button';
import Modal from './pure/Modal/Modal';
import {setWarning} from '../actions/app/appActions';
import configureStore from '../store/configureStore';
const store = configureStore();
export const WarningModal = (props) => {
const {message, withCleanup} = props;
const [
title,
text,
leave,
cancel
] = message.split('|');
const handleOnClick = () => {
props.setWarning(false);
withCleanup(true);
}
return(
<Modal>
<header>{title}</header>
<p>{text}</p>
<Alert />
<div className="modal__buttons-wrapper modal__buttons-wrapper--center">
<button
onClick={() => withCleanup(false)}
className="button modal__close-button button--icon button--icon-only button--text-link"
>
<No />
</button>
<Button id="leave-warning-button" className="button--transparent-bg" onClick={() => handleOnClick()}>{leave}</Button>
<Button id="cancel-warning-button" onClick={() => withCleanup(false)}>{cancel}</Button>
</div>
</Modal>
);
}
WarningModal.propTypes = {
withCleanup: PropTypes.func.isRequired,
message: PropTypes.string.isRequired,
setWarning: PropTypes.func.isRequired
};
const mapStateToProps = state => {
console.log(state)
return {
isWarning: state.app.isWarning
}
};
const WarningModalContainer = connect(mapStateToProps, {
setWarning
})(WarningModal);
export default (message, callback) => {
const modal = document.createElement('div');
document.body.appendChild(modal);
const withCleanup = (answer) => {
ReactDOM.unmountComponentAtNode(modal);
document.body.removeChild(modal);
callback(answer);
};
ReactDOM.render(
<Provider store={store}>
<WarningModalContainer
message={message}
withCleanup={withCleanup}
/>
</Provider>,
modal
);
};
the issue I have is that 'setWarning' doesn't update the state, it does get called as I have a debugger inside the action and the reducer but the actual property doesn't not change to 'false' when:
props.setWarning(false);
gets called.
I use the following to trigger the custom modal:
const togglePromptCondition =
location.hash === '#access-templates' || location.hash === '#security-groups'
? promptCondition
: isFormDirty || isWarning;
<Prompt message={promptMessage} when={togglePromptCondition} />
To test this even further I have added 2 buttons in the application to toggle 'isWarning' (the state property I am talking about) and it works as expected.
I think that although WarningModal is connected in actual fact it isn't.
REDUCER
...
case SET_WARNING:
console.log('reducer called: ', action)
return {
...state,
isWarning: action.payload
};
...
ACTION
...
export const setWarning = status => {
console.log('action called')
return {
type: SET_WARNING,
payload: status
}
};
...
UPDATE
After having to incorporates the following:
const mapStateToProps = state => {
return {
isWarning: state.app.isWarning
}
};
const mapDispatchToProps = dispatch => {
return {
setWarning: (status) => dispatch({ type: 'SET_WARNING', payload: status })
}
};
I am now getting:
Maybe this could help?
You have to dispatch the actions in the action creator and the type of the action to dispatch should be always string.
Try this
const mapStateToProps = state => {
console.log(state)
return {
isWarning: state.app.isWarning
}
};
const mapDispatchToProps = dispatch => {
console.log(dispatch)
return {
setWarning: (status) => dispatch({ type: 'SET_WARNING', payload: status })
}
};
const WarningModalContainer = connect(mapStateToProps, mapDispatchToProps)(WarningModal);
REDUCER
...
case 'SET_WARNING':
console.log('reducer called: ', action)
return {
...state,
isWarning: action.payload
};
...

React-Reudx: Actions must be plain objects. Use custom middleware for async actions

I made a counter example with react-redux, but there seems to be errors.
error message is 'Actions must be plain objects. Use custom middleware for async actions.'
And error line is
const mapDispatchToProps = dispatch => {
15 | return {
> 16 | handleIncrease: () => dispatch(actions.increase()),
17 | handleDecrease: () => dispatch(actions.decrease())
18 | };
19 | };
---------------=--------------
First, actions/actionTypes.js
export const INCREASE = "INCREASE";
export const DECREASE = "DECREASE";
actions/index.js
import * as types from "./actionTypes";
export const increase = number => {
type: types.INCREASE, number;
};
export const decrease = number => {
type: types.DECREASE, number;
};
reducers/index.js
import { combineReducers } from "redux";
import number from "./number";
const reducers = combineReducers({
number
});
export default reducers;
reducers/number.js
import * as types from "../actions/actionTypes";
const number = (state = 0, action) => {
switch (action.type) {
case types.INCREASE:
return { ...state, number: action.number + 1 };
case types.DECREASE:
return { ...state, number: action.number - 1 };
default:
return state;
}
};
export default number;
components/Counter.js
import React, { Component } from "react";
export default class Counter extends Component {
render() {
const { number, onIncrease, onDecrease } = this.props;
return (
<div>
<h1>Counter</h1>
<div>Value: {number}</div>
<button onClick={onIncrease}>+</button>
<button onClick={onDecrease}>-</button>
</div>
);
}
}
Last, App.js
import React, { Component } from "react";
import "./App.css";
import Counter from "./components/Counter";
import { connect } from "react-redux";
import * as actions from "./actions";
const mapStateToProps = state => {
return {
number: state.number
};
};
const mapDispatchToProps = dispatch => {
return {
handleIncrease: () => dispatch(actions.increase()),
handleDecrease: () => dispatch(actions.decrease())
};
};
class App extends Component {
render() {
return (
<div className="App">
<Counter
number={this.props.number}
onIncrease={this.props.handleIncrease}
onDecrease={this.props.handleDecrease}
/>
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
Which part is wrong?
I am curious too.
Thanks.
I fix this error, but next occurs new error
error message is
Uncaught Error: Objects are not valid as a React child (found: object with keys {number}). If you meant to render a collection of children, use an array instead.
in div (at Counter.js:9)
in div (at Counter.js:7)
in Counter (at App.js:25)
in div (at App.js:24)
in App (created by Connect(App))
in Connect(App) (at index.js:16)
in Provider (at index.js:15)
at invariant (invariant.js:42)
at throwOnInvalidObjectType (react-dom.development.js:7362)
at updateSlot (react-dom.development.js:7631)
at reconcileChildrenArray (react-dom.development.js:7762)
at reconcileChildFibers (react-dom.development.js:8121)
at reconcileChildrenAtExpirationTime (react-dom.development.js:8248)
at reconcileChildren (react-dom.development.js:8231)
at updateHostComponent (react-dom.development.js:8539)
at beginWork (react-dom.development.js:8986)
at performUnitOfWork (react-dom.development.js:11814)
at workLoop (react-dom.development.js:11843)
at HTMLUnknownElement.callCallback (react-dom.development.js:100)
at Object.invokeGuardedCallbackDev (react-dom.development.js:138)
at invokeGuardedCallback (react-dom.development.js:187)
at replayUnitOfWork (react-dom.development.js:11318)
at renderRoot (react-dom.development.js:11885)
at performWorkOnRoot (react-dom.development.js:12449)
at performWork (react-dom.development.js:12370)
at performSyncWork (react-dom.development.js:12347)
at interactiveUpdates (react-dom.development.js:12597)
at interactiveUpdates (react-dom.development.js:1958)
at dispatchInteractiveEvent (react-dom.development.js:4259)
You do not return anything here:
export const increase = number => {
type: types.INCREASE, number;
};
export const decrease = number => {
type: types.DECREASE, number;
};
Fix it by actually returning an object:
export const increase = number => {
return {
type: types.INCREASE, number
}
};
export const decrease = number => {
return {
type: types.DECREASE, number
}
};
or more concise:
export const increase = number => ({
type: types.INCREASE, number;
});
export const decrease = number => ({
type: types.DECREASE, number;
});
EDIT:
You also need to fix the reducer:
const number = (state = 0, action) => {
switch (action.type) {
case types.INCREASE:
return state + 1;
case types.DECREASE:
return state - 1;
default:
return state;
}
};
a state is a sole Number so you don't need to copy any values. You were returning an object from your reducer that's why react couldn't render it.
I never see you use bindActionCreators.
example
const {createStore, bindActionCreators} = Redux;
const {Component} = React;
const { connect, Provider } = ReactRedux;
const TestClicker = (props) => {
return(
<button onClick={props.onClick}>Click Me</button>
)
}
class App extends React.Component {
constructor(){
super();
}
render(){
return(
<div>
<h1>Hello</h1>
<p>{this.props.work}</p>
<TestClicker onClick={this.props.testAction}/>
<TestClicker onClick={this.props.testAction2}/>
<TestClicker onClick={this.props.testAction3}/>
</div>
);
}
}
function mapStateToProps(state){
return {
work: state.working
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({
testAction: changeAc1,
testAction2: changeAc2,
testAction3: changeAc3
}, dispatch);
}
App = connect(mapStateToProps, mapDispatchToProps)(App);
const changeAc1 = (action) => {
console.log("I've been clicked");
return {
type: "GO"
}
}
const changeAc2 = (action) => {
console.log("I've been clicked");
return {
type: "YES"
}
}
const changeAc3 = (action) => {
console.log("I've been clicked");
return {
type: "GLOW"
}
}
const initialState = { working: "no" };
const reducer = (state, action) => {
switch(action.type){
case "GO":
return Object.assign({}, state, { working: "yes" });
case "YES":
return Object.assign({}, state, { working: "HELL YESSS!!!" });
case "GLOW":
return Object.assign({}, state, { working: "This is the SHIIIIIIIIZZZZZ" });
default:
return state;
}
}
const store = createStore(reducer, initialState);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
Link to codepen https://codepen.io/ar-traunworks/pen/MrNYqX
You are either mutating the state (try to store number in variable, return the whole state ...state, then the number property mutate that example {...state, number: (the variable)}) or you need to check how you have binded your actions.

mapDispatchToProps dispatch action not working to update State

In my index.js the addCoin action is working.
import { addCoin } from './reducer/portfolio/actions'
const element = document.getElementById('coinhover');
const store = createStore(reducer, compose(
applyMiddleware(thunk),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
));
store.dispatch(addCoin('bitcoin'));
When store.dispatch is called I can see the updated state here.
However I do not want to call dispatch actions from my index.js, but from within my components.
My SearchCoin component:
import React from 'react'
import { connect } from 'react-redux'
import * as R from 'ramda'
import * as api from '../../services/api'
import { addToPortfolio, findCoins } from '../../services/coinFactory'
import { addCoin } from '../../reducer/portfolio/actions'
const mapDispatchToProps = (dispatch) => ({
selectCoin(coin) {
return () => {
dispatch(addCoin(coin))
}
}
});
class SearchCoin extends React.Component {
constructor(props) {
super(props)
this.state = {
searched: []
};
// console.log('props', props);
this.close = this.close.bind(this);
}
componentDidMount() {
this.coinInput.focus();
this.handleChange = this.handleChange.bind(this);
this.clickCoin = this.clickCoin.bind(this);
}
handleChange() {
const text = document.getElementById('coin-search').value;
const search = (text) => this.setState({ searched: findCoins(text) });
const clearSearch = () => this.setState({ searched: [] });
text.length > 1 ? search(text) : clearSearch();
}
clickCoin(coin) {
console.log('clickCoin', coin);
// api.getCoin(coin.id).then((res) => {
// const apiCoin = R.head(res.data);
// addToPortfolio(apiCoin);
// });
this.props.selectCoin(coin);
this.props.closeSearch();
}
close() {
this.props.closeSearch();
}
render() {
const searched = this.state.searched.map((coin) => {
return (
<li key={ coin.id } onClick={ ()=> this.clickCoin(coin) }>
<div className="coin-logo">
<img src={ coin.logo }/>
</div>
<span>{ coin.name }</span>
</li>
);
});
return (
<div id="search-coin-component">
<input type="text"
id="coin-search"
className="coin-search-input fl"
placeholder="Search"
onChange={ ()=> this.handleChange() }
ref={ (input) => { this.coinInput = input; } } />
<div className="icon-cancel-outline fl" onClick={ this.close }></div>
<div className="coin-select">
<ul>
{ searched }
</ul>
</div>
</div>
)
}
}
export default connect(null, mapDispatchToProps)(SearchCoin)
This is the onClick:
<li key={ coin.id } onClick={ ()=> this.clickCoin(coin) }>
At the bottom of the file I am using connect to add mapDispatchToProps
export default connect(null, mapDispatchToProps)(SearchCoin)
Here is the class method clickCoin which calls this.props.selectCoin
clickCoin(coin) {
console.log('clickCoin', coin);
this.props.selectCoin(coin);
this.props.closeSearch();
}
Finally selectCoin
import { addCoin } from '../../reducer/portfolio/actions'
const mapDispatchToProps = (dispatch) => ({
selectCoin(coin) {
return () => {
dispatch(addCoin(coin))
}
}
});
However when I click the button it seems like the dispatch is not fired as nothing happens to the redux state.
import * as R from 'ramda'
import * as api from '../../services/api'
import { addToPortfolio } from '../../services/coinFactory'
export const ADD_COIN = 'ADD_COIN'
export function addCoin(coin) {
console.log('addCoin', coin);
return dispatch =>
api.getCoin(coin)
.then((res) => addToPortfolio(R.head(res.data)))
.then((portfolio) => dispatch(add(portfolio)));
}
// action creator
export function add(portfolio) {
return {
type: ADD_COIN,
portfolio
}
}
The reducer
import { ADD_COIN } from './actions'
const initialState = [];
export default (state = initialState, action) => {
switch(action.type) {
case ADD_COIN:
return action.portfolio;
default:
return state;
}
}
the reducer/index.js
import { combineReducers } from 'redux'
import portfolio from './portfolio'
export default combineReducers({
portfolio
});
Apart from azium answer, you can use actions like this. It saves you some writing,
export default connect(null, {addCoin})(SearchCoin)
and you can use it like this,
clickCoin(coin) {
console.log('clickCoin', coin);
this.props.addCoin(coin);
this.props.closeSearch();
}
The problem is that you are wrapping your function with an extra function.
Change:
const mapDispatchToProps = (dispatch) => ({
selectCoin(coin) {
return () => { <--- returning extra function
dispatch(addCoin(coin))
}
}
})
to:
const mapDispatchToProps = (dispatch) => ({
selectCoin(coin) { dispatch(addCoin(coin)) }
})

Categories

Resources