this.props is not a function (reactjs) - javascript

Have a code that delete element by request
class ArchOrDlt extends Component{
constructor(props) {
super(props)
}
deleteItem(itemId, e) {
console.log(itemId);
this.props.test();
this.props.DeleteListProfileItem(itemId);
}
ArchOrDlt() {
const isdel = this.props.isdel;
const itemId = this.props.itemId;
if (isdel == 1) {
return (<div><a onClick={this.deleteItem.bind(this, itemId)} >delete</a></div>);
}
return (<div>archived</div>);
}
render() {
return (
<div>
{this.ArchOrDlt()}
</div>
);
}
}
If I press link I get Uncaught TypeError: this.props.test is not a function
There I dispatch to props
const mapDispatchToProps = function(dispatch) {
return {
IncomeListProfile: () => dispatch(IncomeProfileList()),
DeleteListProfileItem: (id) => dispatch(DeleteListProfileItem(id)),
openPopUp: () => dispatch(openPopUp()),
test: () => dispatch(test())
}
}
Can't Understand Why it's happen for exaple if I move this.props.test();
to another click, everything working fine, there full component
https://plnkr.co/edit/OEugCIxoAGE8iVb57WOa?p=catalogue

First of all, you should use bindActionCreators function from redux
import { bindActionCreators } from 'redux';
...
const mapDispatchToProps = (dispatch) => {
return {
IncomeListProfile : bindActionCreators(IncomeProfileList, dispatch),
...
}
}
http://redux.js.org/docs/api/bindActionCreators.html

Related

Why history listen is not updating my component's state?

TLDR: I am building a React router app, I trying to update the state of my component through a history listener, this listener works fine I put a console.log and I can see it, but the state of my component is not changing, I can see this with the React chrome extension and my component is not updating.
`
import React from "react";
import { withRouter } from "react-router-dom";
import { styles } from './Styles';
import { url } from './App';
class Searchresults extends React.Component {
constructor(props) {
super(props);
this.state = {
searchResults : []
}
}
async fetchResults(endpoint) {
try {
const response = await fetch(endpoint);
if (response.ok) {
const rJson = await response.json();
return rJson;
}
} catch (err) {
console.log(err);
}
}
componentDidMount() {
this.searchUpdate();
this.unlisten = this.props.history.listen((location, action) => {
console.log("it works!");
this.searchUpdate();
})
}
searchUpdate = () => {
const { location } = this.props;
const params = new URLSearchParams(location);
const query = params.get("search");
const name = query.replace("?name", "s");
const endpoint = url + "&" + name;
this.fetchResults(endpoint).then(response => {
return response['Search'].map(item => {
return { title: item['Title'], poster: item['Poster'], id: item['imdbID'] }
})
}).then(response => {
this.setState({
searchResults : response
})
});
}
render() {
return (
<div style={styles.movieList}>
<ul>
{
!this.state.searchResults? 'Loading' : this.state.searchResults.map((item, index) => {
return (<li key={index}>
<a href={'/moviepage?id=' + item.id}>{item.title}</a><br />
<img src={item.poster} alt="Movie poster"
style={{ width: "6rem", height: "auto" }} />
</li>)
})
}
</ul>
</div>
);
}
}
export default withRouter(Searchresults);
`
I am trying to update the state with a method searchUpdate, then this method is called in componentDidMount, here works fine, then when the URL changes, the history.listen triggers and searchUpdate is fired again, and everything seems to work except the change of the state of my component.
The first .then function in your searchResult function doesn't return a promise, so there is no need to use another .then. Just put the setState call in the same block:
this.fetchResults(endpoint).then(response => {
const searchResults = response['Search'].map(item => {
return { title: item['Title'], poster: item['Poster'], id: item['imdbID'] }
});
this.setState({searchResults})
});

Calling action with Redux-thunk not working

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);
```

ReactJs - How to complete onClick before download - href

I have a simple React button component that when clicked should retrieve and download data on the client browser. The problem I am experiencing is that the download is triggered and the csv file downloaded before the data is passed into the href.
Here is my component:
import { Component } from 'react';
import { connect } from 'react-redux';
import { PropTypes } from 'prop-types';
import { ManageUsersSelectors } from 'selectors/Users';
import { BatchRoleActions } from 'actions/Users';
class UsersExportButton extends Component {
constructor() {
super();
this.state = {
users: ''
};
}
getUsers(){
const { userIds } = this.props;
BatchRoleActions.getAllRoleUsers(userIds)
.then((users) => {
this.setState({ users: users});
return this.state.users;
});
}
render() {
return (
<div className="roles-export-button">
<a className="button button-default" href={this.state.users} download={'roles.csv'} onClick={() => this.getUsers()} return true>Export Csv</a>
</div>
);
}
}
function mapStateToProps(state) {
const userIds = ManageUsersSelectors.batchUserIdsSelector(state);
return {
userIds: userIds
};
}
UsersExportButton.propTypes = {
text: PropTypes.string.isRequired,
data: PropTypes.array
};
export default connect(mapStateToProps)(UsersExportButton);
How can I get the getUsers()/onClick function to complete the data retrieval step before downloading?
When i debug my code I can see that the getUsers function returns data - however after the download is triggered
Make sure to bind this to your functions. In your constructor you can do:
constructor() {
super();
this.state = {
users: ''
};
this.getUsers = this.getUsers.bind(this);
}
or you can use the bind this function:
getUsers = () => {
const { userIds } = this.props;
BatchRoleActions.getAllRoleUsers(userIds)
.then((users) => {
this.setState({ users: users});
return this.state.users; // This should be removed, you can use this.state.users throughout this component.
});
}
Why not get the user data in the componentDidMount lifecycle method? It doesn't look like it needs to be called onClick.
{
// ...
componentDidMount() {
this.getUsers();
}
// ...
render() {
return (
<div className="roles-export-button">
<a className="button button-default" href={this.state.users} download={'roles.csv'}>Export Csv</a>
</div>
)
}
}
How about handling the default "link" behaviour manually to get more control? Also you should probably try to access state after setState has been executed via its callback.
e.g.
getUsers(cb){
const { userIds } = this.props;
BatchRoleActions.getAllRoleUsers(userIds)
.then((users) => {
// note the callback of setState which is invoked
// when this.state has been set
this.setState({ users: users }, cb);
});
}
const handleClick = () => {
this.getUsers(() => {
window.open(this.state.whatever)
})
}
<span onClick={handleClick}>Export Csv</span>

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)) }
})

Component props.dispatch doesnt work. React redux

I need help. In my colorcontrol I am trying to do a this.props.dispatch(triggerFBEvent(fbID, method, params)) with no luck.
What works though is if I were to just do just triggerFBEvent(fbID, method, params). I am getting the error:
index.bundle.js:61968 Uncaught TypeError: this.props.dispatch is not a function
What I am trying to accomplish is to be able to send in new props with the line above, and then on
componentWillMount() {
this.props.dispatch(fetchFBEvent(this.props.fbID, "getColor"))
}
Call a custom service to update state with appropriate colors. But this.props.dispatch is not a function there either.
import React from 'react'
import { connect } from 'react-redux'
import {triggerFBEvent, triggerFBClearEvent, fetchFBEvent} from '../actions/functionblocksActions'
`
import { CustomPicker, HuePicker, SaturationPicker, SliderPicker, CustomPointer } from 'react-color';
#connect((store) => {
return {
fb: store.functionblocks.functionblock
}
})
export default class Functionblock extends React.Component {
constructor(props) {
super(props);
this.state = {
};
this._getType = this._getType.bind(this)
}
_getType (wanted) {
const { fbID, fbName, func } = this.props;
let type;
let types = {
'com.xxxx.xx.service.dal.functions.Alarm': function () {
type = <Alarm fbID={fbID} fbName={fbName}/>;
},
'com.xxxx.xxx.service.dal.functions.BooleanControl': function () {
type = <BooleanControl fbID={fbID} fbName={fbName}/>;
},
'com.xxx.xxxx.service.dal.functions.BooleanSensor': function () {
type = <BooleanSensor fbID={fbID} fbName={fbName} />;
},
'com.xxxx.xxx.service.dal.functions.ColorControl': function () {
type = <ColorControl func={func} fbID={fbID} fbName={fbName} />;
}
'default': function () {
type = <WakeUp fbID={fbID} fbName={fbName} />;
}
};
// invoke it
(types[wanted] || types['default'])();
// return a String with chosen type
return type;
}
render() {
const { fbID, fbName, func } = this.props;
const type = this._getType(func.serviceProperties["clazz"]);
return(
<div>
{type}
</div>
)
}
}
// Classes for the different functions.
class ColorControl extends React.Component {
componentWillMount() {
this.props.dispatch(fetchFBEvent(this.props.fbID, "getColor"))
}
constructor(props) {
super(props);
this.state = {
color: {
h: 150.3197479248047,
s: 0.5,
l: 0.5
}
}
this.onChangeComplete = this.onChangeComplete.bind(this);
}
componentWillReceiveProps(nextProps) {
alert("YEP")
// let home = this._getHome(nextProps.areas, nextProps.statics);
// if(home!=null){
// this.setState({
// inputHome: home.name,
// })
// }
}
onChangeComplete(color, event) {
let hsl = color.hsl;
let hue = color.hsl.h / 360;
let saturation = color.hsl.s;
let lightness = color.hsl.l;
this.setState({ color: hsl })
// Update props
let fbID = this.props.fbID;
let method = "setColor";
let params = {"hue": hue, "sat": saturation, "light": lightness};
this.props.dispatch(triggerFBEvent(fbID, method, params))
}
_defineFunction(){
}
render() {
return (<div>
<SliderPicker {...this.props}
pointer={ CustomPointer }
color={this.state.color}
onChangeComplete={ this.onChangeComplete }
direction={ 'horizontal' || 'vertical' }/>
</div>
)
}
}
Can anyone help me understand whats going wrong?
You need to connect ColorControl to Redux, otherwise it doesn't get a dispatch prop.
#connect()
class ColorControl extends React.Component {
Here is the codebase to use your actions without problems.
import * as actions from './YourActionsPath'
import { bindActionCreators } from 'redux'
#connect(
state => ({
yourDerivedState : state.somePath
}),
dispatch => ({
actions : bindActionCreators( actions, dispatch )
})
)
export default class YourClass extends Component {
someMethod(){
this.props.actions.yourAction() // call it with no problems
}
render(){
return (
// your html
)
}
}
I hope you get the idea. If you use this patterns, you won't have problems.
As you can use your derived state as this.props.derivedState, which you define in the connect, you can also use your actions you defined on the connect.
Besides you can use this.props.dispatch if you connected your component. In case you need it as in your case, but this makes the code less clear and leads to maintainance problems.
import { createStore } from 'redux'
let store = createStore(//define reducer,preload state and enhancer)
//call action
store.dispatch(triggerFBEvent(fbID, method, params))

Categories

Resources