react redux dispatch fuction is not triggered - reactjs

i attach all my required files below for references
when i try to call react redux dispatch fuction is not triggered. am new to react redux
action.js file
import { ITS_USER } from './types';
import {store} from './index'
export function addPerson(person) {
console.log("chek",person);
console.log("state",store.getState());
return dispatch => {
dispatch(adduser(person));
}
}
export function adduser(person){
return {
type: ITS_USER,
payload: person
};
}
Reducer.js
import { ITS_USER } from './types';
export default function(state=[], action) {
console.log("dxasdads",action.type)
switch (action.type) {
case ITS_USER:
return action.payload;
default:
return state;
}
}
triger function call
**var person="praveen"
addPerson(person)**

You have to connect your component with connect HOC provided by react-redux libary, then you can trigger a dispatch function by dispatching it from mapStateToProps passed as a first argument to connect function. Something like this:
import YOUR_COMPONENT from './PATH_TO_YOUR_COMPONENT'
const mapDispatchToProps = dispatch => ({
addPerson: (person) => dispatch(addPerson(person)),
});
export default connect(null, mapDispatchToProps)(YOUR_COMPONENT);
And then inside your component, you will get addPerson function as your component props. You can simply call it by this.props.addPerson(person).

Related

react-redux dispatch undefined

In my App.js :
const initialAppState = {
nums: {},
};
const reducer = (state = initialAppState, action) => {
if (
action.a === undefined ||
action.b === undefined ||
action.c === undefined
) {
return state;
}
if (state.nums[action.a][action.b] === undefined) {
state.nums[action.a][action.b] = {};
}
return {
nums: (state.nums[action.a][action.b] =
action.c),
};
};
const store = createStore(reducer);
Then passed it with Provider.
When in my Test.js I'm trying to change the value it give me error :
const mapStateToProps = (state) => {
return {
nums: state.nums,
};
};
function mapDispatchToProps(dispatch) {
return {
add: (a, b, c) =>
dispatch({a: a, b: b, c: c}),
};
}
export default connect(mapStateToProps, mapDispatchToProps())(Test);
And the Test functional component looks like this :
function Test({nums, dispatch})
...
function add(data, count) {
dispatch.add('1','2','3');
}
It give me error saying : TypeError: undefined is not an object (evaluating 'dispatch.add')
Shouldn't it recognize dispatch as dispatch is Test's parameter, and add is another function of that functional component ?
It’s not dispatch.add() its props.add()
// add comes in as a prop. that’s why it’s called map dispatch to props.
function Test({nums, add: doAdd})
...
function add(data, count) {
doAdd('1','2','3');
}
I would recommend you organize your code. Try to move actions and reducers into separate files like actions.js, reducers.js.
REDUCER NEED SOME FIXES:
In your example of reducer in the last return you are trying to mutate state.
Also as you can see in your second if there are no return.
PROPOSAL OF ACTIONS AND REDUCERS SEPARATION
Inside your App.js you will createStore:
//App.js
import { reducer } from "./reducers"
const store = createStore(reducer);
<Provider store={ store }>
...
</Provider>
Now let's do actions.js file:
//actions.js
export const ADD_ACTION='ADD_ACTION' // action type
export function addAction(data) {
return { type: ADD_ACTION, data }
}
In reducers you'll move part of code from your App.js. I recommend you to use switch inside your reducer like that:
//reducers.js
import { ADD_ACTION } from "./actions";
const initialAppState = {
nums: {},
};
export const reducer = (state = initialAppState, action) => {
switch(action.type) {
case ADD_ACTION:
return Object.assign({}, state, { nums: action.data });
default:
return state
}
};
As you can see one of the ADD_ACTION is returning new object with updated nums value. This is because one of the essential Redux rules is "Do not mutate state".
Now, let's try our action in Test.js. First import addAction from actions.js. Then call dispatch with addAction as an argument.
//Test.js functional component version
import { addAction } from "./actions";
function Test({dispatch}) {
...
function add(data, count) {
dispatch(addAction(data));
}
}
export default connect(null, null)(Test);
Component receives dispatch from connect. Connect has (null, null) because in this case we are not using mapStateToProps, nor mapDispatchToProps.
Extra tip: For class component you'll use action in a little bit different way.
//Test.js Class component version
import React from 'react';
import { addAction } from "./actions";
import { connect } from 'react-redux';
class TestClass extends React.Component {
render() {
return(
<button onClick={() => this.props.addAction(2)}>Action</button>
)
}
}
const mapDispatchToProps = ({
addAction
});
export default connect(null, mapDispatchToProps)(TestClass);
In class component example you'll call action with value 2 when onClick event fires.
Working sandbox example: react-redux example

Calling action creator inside the function. Error:Actions may not have an undefined "type" property?

I know action creator should have a type of property only then it would be able to dispatch. Since I am having a function call which ultimately leads to one action creator which have type property then Why it is showing me this problem.
When I tried to directly dispatch start game action creator it works but since I have to implement some more function inside them so I needed then inside the function.
How to implement the same?
Menu.js
import React, { Component } from 'react';
import {connect} from 'react-redux';
import {startGame} from '../actions';
import {loadMenu} from '../actions';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
const page_Banner={
marginTop:'35px',
fontSize:'45px',
textAlign:'center',
letterSpacing:'20px',
fontWeight:'bold'
};
const spacebar_screen={
marginTop:'35px',
color:'grey'
}
class Menu extends Component {
componentDidMount() {
this.props.dispatch(loadMenu());
console.log(this.props.dispatch);
console.log(this.props.isPlaying);
}
render() {
return (
<div style={page_Banner}>
Redux Tetris
{!this.props.isPlaying?<h2 style={spacebar_screen}>Press spacebar to start the game</h2>:null}
</div>
)
}
}
Menu.propTypes={
isPlaying:PropTypes.bool,
}
// function mapDispatchToProps(dispatch){
// return bindActionCreators({loading:loadMenu},dispatch);
// }
const mapStateToProps = (state) => ({
isPlaying: state.gameStatus.currentState !== 'IDLE',
});
export default connect(mapStateToProps)(Menu);
Action.js
import constants from "../gameConstants/constants";
export const startGame=()=>{
const ShapeMapping=constants;
const current_Shapeno=Math.floor(Math.random()*7);
const next_Shapeno=Math.floor(Math.random()*7);
const current_Shape=ShapeMapping[current_Shapeno];
const next_Shape=ShapeMapping[next_Shapeno];
return {
type:"START_GAME",
current_Shape,
next_Shape
};
}
export const pauseGame = () => ({
type: "PAUSE_GAME",
});
export const unpauseGame = () => ({
type: "UNPAUSE_GAME",
});
export const gameOver = () => ({
type: "GAME_OVER",
});
export const loadMenu=()=>({
function(dispatch,getState){
function handleSpacebar(event){
if(event.keyCode==32){
dispatch(loadGame());
window.removeEventListener('keyup',handleSpacebar);
console.log('here')
}
}
window.addEventListener('keyup',handleSpacebar);
}
})
export const loadGame=()=>({
function (dispatch,getState){
dispatch(startGame());
}
})
The issue is in loadMenu and loadGame action creators. You're returning an object with an anonymous function which doesn't make any sense. An action creator is supposed to return an object with a type and the minimal data to define the action and return a function if you're using redux-thunk.
Keep the actions creators clean like you've done in gameOver and handle everything else in reducers or using the redux pub/sub pattern.
See this answer by Dan Abramov https://github.com/reduxjs/redux/issues/787

How to get dispatch function reference and action creater as a props inside any connected component

we get dispatch function ref in our connected component but when we use action creator argument in our connect function then it will not return dispatch function as previously.
Case 1. With only first param of connect function.
import React, { Component } from 'react';
import { connect } from 'react-redux';
class App extends Component {
render() {
console.log('this.props',this.props)
return (
<div className="App">
App
</div>
);
}
}
const mapStateToProps = (state) => {
return state
}
export default connect(mapStateToProps)(App);
Case 2. Use connect's second parameter also
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { setData } from './actions'
class App extends Component {
render() {
console.log('this.props',this.props)
return (
<div className="App">
App
</div>
);
}
}
const mapStateToProps = (state) => {
return state
}
export default connect(mapStateToProps,{ setData })(App);
I expect that in second case, dispatch function ref should also be listed in props, but its not happend .
Console output :
case 1. dispatch is showing in props https://prnt.sc/ne0fpb
case 2. No dispatch get in props https://prnt.sc/ne0djb
So please help me why i am not getting dispatch function in case 2?
Second connect parameter (mapDispatchToProps) defaults to dispatch => ({ dispatch }) function. Default value isn't applied when it's specified.
Since mapDispatchToProps is used to provide all needed dispatcher functions as component props, dispatch prop isn't needed.

Redux action is undefined outside the Promise

I've been using async calls with Redux + Promise Middleware like this:
export function getAllFiles() {
const request = axios.get(`${URL}/files`).then(res => res.data);
return { type: "GET_FILES", payload: request };
}
So far it worked, since from my understanding Promise Middleware takes care of this. Also, if I console.log(res.data) inside .then, I will get expected result. However, when I check it from reducer file it's undefined. Can someone please school me if I'm missing something huge.
import React, { Component } from "react";
import { connect } from "react-redux";
import Info from "./../components/Info/info";
import { getAllFiles } from "./../actions";
class HomeContainer extends Component {
componentWillMount = () => {
this.props.dispatch(getAllFiles);
};
render() {
console.log(this.props);
return (
<div>
<Info />
</div>
);
}
}
function mapStateToProps(state) {
return {
files: state.files
};
}
export default connect(mapStateToProps)(HomeContainer);
import { combineReducers } from "redux";
import fileReducer from "./file_reducer.js";
const rootReducer = combineReducers({ wineReducer });
export default rootReducer;
// file_reducer.js
export default function(state = {}, action) {
switch (action.type) {
case "GET_FILES":
return {...state, files: action.payload}
default:
return state;
}
}
The main problem here is your treating, what is clearly an async action, as a synchronous one.
The redux store by default will only deal with action objects, in your case since you need to wait for a result before we fire the action object, we need some middleware to allow the store to handle this.
Have a look at the applyMiddleware function, plenty of links to common thunk middleware and code samples.

Redux woes: switch statement not registering action.type and not executing correct action

I am new with Redux and, to be honest, find it to be rather difficult and not intuitive at all to use. What I am trying to accomplish is just to load data from a file inside my app into a view just to get reducers and actions working correctly. I have a switch statement inside a projects_reducer.js file, an actions index.js, a projects.js view, and a reducer index.js as well. I've logged it out and the switch statement seems to be skipping the Fetch_Projects action every time and going to the default because action.type is not being registered correctly. I don't know why this is. Any help is appreciated. My code is included below.
//actions index.js file, only top two actions are relevant
import {Registrants, Projects} from '../../data';
export const Fetch_Users="Fetch_Users";
export const Fetch_Projects="Fetch_Projects";
export const Add_Project="Add_Project";
export const Add_User="Add_User";
export const Add_File="Add_File";
export const Delete_User="Delete_User";
export const Delete_Project="Delete_Project";
export const Delete_File="Delete_File";
export function fetchUsers(){
return {
type: Fetch_Users,
payload: Registrants
}
}
export function fetchProjects(){
console.log("the fetch projects action!");
return {
type: Fetch_Projects,
payload: Projects
}
}
export function addUser(){
return {
type: Add_User,
payload: "stuff"
}
}
export function addProject(){
return {
type: Add_Project,
payload: "stuff"
}
}
export function addFile(){
return {
type: Add_File,
payload: "stuff"
}
}
export function deleteUser(){
return {
type: Delete_User,
payload: "stuff"
}
}
export function deleteProject(){
return {
type: Delete_Project,
payload: "stuff"
}
}
export function deleteFile(){
return {
type: Delete_File,
payload: "stuff"
}
}
projects_reducer.js file
import {Fetch_Projects, Add_Project, Delete_Project} from '../actions';
import {Registrants, Projects} from '../../data';
export default function(state={}, action){
console.log("payload", action);
switch(action.type){
case Fetch_Projects:
return Projects;
case Add_Project:
return state;
case Delete_Project:
return state;
default:
console.log("Well, you hit the default... :(")
return state;
}
}
reducers index.js
import {combineReducers} from 'redux';
import {reducer as formReducer} from 'redux-form';
import ProjectsReducer from './projects_reducer';
const rootReducer=combineReducers({
projects: ProjectsReducer
//form: formReducer
});
export default rootReducer;
projects.js view
import React, {Component} from 'react';
import {connect} from 'react-redux';
import Table from './table';
import {fetchProjects} from '../actions';
class Projects extends Component{
componentDidMount(){
fetchProjects();
console.log("props", this.props);
}
render(){
return (
<div>
<Table />
</div>
)
}
}
function mapStateToProps(state){
return {projects: state.projects}
}
export default connect(mapStateToProps, {fetchProjects})(Projects);
In order to get an action to call your reducer and get the expected result, you must call your action by dispatching your action. In docs you can see this.
This is the only way to trigger a state change.
In your componentDidMount where you call fetchProjects, you are just calling a function, but not dispatching a function.
What you want to do is define the mapDispatchToProps function and attach the dispatch call to you fethcProjects function there.
Here is an example if that.
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch)
}
}
Although this example shows the usage of bindActionCreators, I should point out that there are ways of doing it without that which you can find in the docs.
The docs for this can be found here.
Alternatively, you can just bring in your store directly and call store.dispatch(fetchProjects()), but this is not the standard approach and I am merely demonstrating the usage of dispatch.
To anyone who might reference this question later, I did manage to solve this problem and the difficulty seems to have come from how I was calling the fetchProjects action in the projects.js view. I was calling it as just fetchProjects(), while the correct call was this.props.fetchProjects(). This must mean that react-redux adds the function(s) that you supply as mapDispatchToProps to props for you to call, although this is pretty tricky to a novice or the react-redux uninitiated.

Resources