Why reducer does not respond to the action? - reactjs

trying to make reducer works, but everytime "default" case fires.
Here is the code:
AC:
import {INPUT_IDEA_HANDLE} from "./types"
export function inputIdeaHandle(idea) {
console.log('it is working, I have access to the idea');
return {
type: INPUT_IDEA_HANDLE,
payload: idea
}
}
Reducer :
import {INPUT_IDEA_HANDLE} from "../actions/types"
export default function (state = null, action) {
switch (action.type) {
case INPUT_IDEA_HANDLE :
console.log('never fires');
return action.payload;
default:
console.log('fires everytime');
return state
}
}
import { combineReducers } from "redux";
import inputIdeaReducer from "./inputIdeaReducer.js"
export default combineReducers({
inputIdea: inputIdeaReducer
});
UPDATE
I changed my trigger code, but keep getting
Cannot read property 'props' of undefined
in return this.props.inputHandle(value);
Event trigger :
import React, { Component } from "react";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import { inputIdeaHandle } from "../actions";
class Dashboard extends Component {
changeHandle(e) {
e.preventDefault();
let value = e.target.value;
return this.props.inputHandle(value);
}
render() {
return (
<div className="dashboard container">
<div className="row">
<div className="col-12">
<h4>Type your idea here</h4>
<input
type="text"
onChange={this.changeHandle}
value={this.props.inputIdea}
/>
</div>
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
inputIdea: state.inputIdea
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(
{
inputHandle: inputIdeaHandle
},
dispatch
);
}
export default connect(mapStateToProps, mapDispatchToProps)(Dashboard);
Triple checked everything, but still keep getting 'fires everytime' in console. Count on you, guys
Regards

Issue is with handling this context.
You can handle this context as follows
constructor
constructor() {
super(props);
this.changeHandle = this.changeHandle.bind(this)};
}
Arrow function in render : onChange={e => this.changeHandle(e)}
React.createClass : React binds all functions to this.
Bind in render:
onChange={this.changeHandle.bind(this)}

import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
you have to import your actions from your action file
import { postSelected } from '../containers/actions';
class Home extends Component {
changeHandle(e) {
e.preventDefault();
let value = e.target.value;
return this.props.post(value);
}
<input type="text" onChange={this.changeHandle} />
} //end of class
function mapStateToProps(state) {
return{
view: state.view
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({
post: postSelected,
},dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(Dashboard);
this should work edit it to suit your needs

Related

State is empty when using mapStateToProps

The state is empty when I try to map the state from the store to the properties of a component. I try to get a value of a string displayed in JSX but it is missing. I cant manage to get anything to display from the redux store.
Reducer:
const initialState = {
visibles: "false",
error: null,
text: ""
};
const rootReducer = (
state = initialState,
action
) => {
switch (action.type) {
case "OPEN_MODAL":
return {
...state,
visibles: "true",
error: null
};
default:
return state;
}
}
export default rootReducer;
and index.js
import {createStore } from "redux";
import {Provider } from "react-redux";
import rootReducer from "./components/Redux/Reducer";
const store = createStore(rootReducer);
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));
consumer of the redux store
import React, { Component } from 'react'
import {connect} from "react-redux";
import styles from "./modal.module.css";
export class Modal extends Component {
render() {
console.log(this.props)
return (
<div className={styles.root}>
<p className={styles.title}>{this.props.visible}</p>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
visible: state.visibles
}
}
export default connect(mapStateToProps)(Modal)
Found the reason why. I had to refactor the Modal class to not use "export class" and then I could get the state from the store with connect.
class Modal extends React.Component {
render() {
console.log(this.props)
return (
<div className={styles.root}>
<p className={styles.title}>{this.props.visible}</p>
</div>
)
}}

React with Redux: returns incorrect state object

I have React with Redux and Electron project. I try to save current screen id to redux and get the saved state on next screen. The problem is, that when I use getSettings, the return value should be my saved state:
Object{settings: Object}
but is action's object:
Object{type: "GET_SETTINGS", payload: ""}
When I put console log to reducer_settings.js, it show correct state. So it seems it is something with binding the getSettings method. Thanks for your help
containers/screen_picker.js:
import React, {Component} from 'react';
import Navigation from "../components/navigation";
const {desktopCapturer, ipcRenderer} = require('electron');
import {connect} from 'react-redux';
const domify = require('domify')
import App from '../components/app'
import {bindActionCreators} from 'redux';
import {setSettings, getSettings} from "../actions/index";
class ScreenPicker extends App {
constructor(){
super();
this.showPicker();
}
showPicker(){
ipcRenderer.send('show-picker', { types: ['screen'] });
ipcRenderer.on('get-sources', (event, options) => {
desktopCapturer.getSources(options, (error, sources) => {
if (error) throw error
let sourcesList = document.querySelector('.capturer-list')
for (let source of sources) {
let thumb = source.thumbnail.toDataURL()
if (!thumb) continue
let title = source.name.slice(0, 20)
let item = `<li><img src="${thumb}"><span>${title}</span></li>`
sourcesList.appendChild(domify(item))
}
let links = sourcesList.querySelectorAll('a')
for (let i = 0; i < links.length; ++i) {
let closure = (i) => {
return (e) => {
e.preventDefault()
// ipcRenderer.send('source-id-selected', sources[i].id)
// sourcesList.innerHTML = ''
this.props.setSettings({
screenId: sources[i].id
});
}
}
links[i].onclick = closure(i)
}
})
})
}
render() {
return (
<div className="window-wrapper">
<div className="main-content">
<div className="capturer-container dn">
<div className="cr">
<p className="mbl">Select the window you want to share:</p>
<ul className="capturer-list"></ul>
</div>
</div>
</div>
<Navigation nextRouteUrl="/camera-test" backRouteUrl="/" />
</div>
)
}
}
function mapStateToProps(state){
return {
settings: state.settings
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({setSettings, getSettings}, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(ScreenPicker);
containers/camera_test.js
const {ipcRenderer} = require('electron');
import React, {Component} from 'react';
import Navigation from "../components/navigation";
import {connect} from 'react-redux';
import App from '../components/app'
import {bindActionCreators} from 'redux';
import {getSettings} from "../actions/index";
class CameraTest extends App {
constructor(){
super();
}
componentDidMount() {
console.log("settings in camera test start");
console.log(this.props.getSettings());
console.log("settings in camera test end");
ipcRenderer.send('stepWindow:create', { });
}
render() {
return (
<div className="window-wrapper">
<div className="main-content">
CameraTest div
</div>
<Navigation nextRouteUrl="/camera-test" backRouteUrl="/screen-picker" />
</div>
)
}
}
function mapStateToProps(state){
return {
settings: state.settings
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({getSettings}, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(CameraTest);
reducers/reducer_settings.js:
import {GET_SETTINGS, SET_SETTINGS} from "../actions/index";
export default function (state = {},action) {
let newState;
switch (action.type){
case GET_SETTINGS:
console.log("reducer GET_SETTINGS");
console.log(state);
return state;
case SET_SETTINGS:
newState = { ...state, ["settings"]: action.payload };
console.log("Start newstate");
console.log(newState);
console.log("End newstate");
return newState;
default:
return state
}
}
actions/index.js
export const SET_SETTINGS = 'SET_SETTINGS';
export const GET_SETTINGS = 'GET_SETTINGS';
export function setSettings(values, callback){
return {
type: SET_SETTINGS,
payload: values
}
}
export function getSettings(){
console.log("actions#getSettings");
return {
type: GET_SETTINGS,
payload: ""
}
}
you dont need the getSetting action creator.
in your component did mount access the settings like this.
componentDidMount() {
console.log("settings in camera test start");
const { settings} = this.props;
console.log(settings);
console.log("settings in camera test end");
ipcRenderer.send('stepWindow:create', { });
}
assuming your object is called settings. normally the object is given the name you are exporting in the reducer. so if you are not able to see an object called settings in props, you need to give your reducer function a name
export default function settings (state = {},action) {
let newState;
switch (action.type){
case GET_SETTINGS:
console.log("reducer GET_SETTINGS");
console.log(state);
return state;
case SET_SETTINGS:
newState = { ...state, ["settings"]: action.payload };
console.log("Start newstate");
console.log(newState);
console.log("End newstate");
return newState;
default:
return state
}
}
EDIT: its mapStateToProps which gives the object name is props.

Dispatch Redux action in React

I'm trying to fetch test API using FetchAPI and Redux.
The problem is with dispatch redux action.
Here's my code:
ProductList.js
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as productActions from '../actions/product';
import RaisedButton from 'material-ui/RaisedButton';
function fetchProductsWithRedux() {
console.log("fetchProductsWithRedux-1");
return (dispatch) => {
console.log("fetchProductsWithRedux-2");
dispatch(this.props.action.fetchProdutcsRequest());
return fetchProdutcs().then(([response, json]) => {
if (response.status === 200) {
console.log("success");
dispatch(this.props.action.fetchProductsSucesss(json))
}
else {
console.log("error");
dispatch(this.props.action.fetchProductsError())
}
})
}
}
function fetchProdutcs() {
const URL = "https://jsonplaceholder.typicode.com/posts";
return fetch(URL, { method: 'GET' })
.then(response => Promise.all([response, response.json()]));
}
class ProductList extends Component {
constructor(props) {
super(props);
this.state = {
productList: [
'product 1',
'product 2',
'product 3'
]
}
}
componentDidMount() {
fetchProductsWithRedux();
}
render() {
return (
<div className="ProductList">
<h2>Products</h2>
<ul>
{
this.props.posts &&
this.props.posts.map((post) => {
return (
<li>{post.title}</li>
)
})
}
</ul>
<ol>
<RaisedButton label="Get Products Action" onClick={this.props.action.getProducts} />
</ol>
</div>
);
}
}
function mapStateToProps(state, props) {
return {
product: state.product,
posts: state.posts
};
}
function mapDispatchToProps(dispatch) {
return {
action: bindActionCreators(productActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ProductList);
product.js (actions)
export function fetchProductsRequest() {
console.log('fetchProductsRequest');
return {
type: 'FETCH_PRODUCTS_REQUEST'
}
}
export function fetchProductsSuccess(payload) {
console.log('fetchProductsSuccess');
return {
type: 'FETCH_PRODUCTS_SUCCESS'
}
}
export function fetchProductsError() {
console.log('fetchProductsError');
return {
type: 'FETCH_PRODUCTS_ERROR'
}
}
product.js (reducer)
export default(state = [], payload) => {
switch (payload.type) {
case 'FETCH_PRODUCTS_REQUEST':
console.log('FETCH_PRODUCTS_REQUEST action');
return state;
case 'FETCH_PRODUCTS_SUCCESS':
console.log('FETCH_PRODUCTS_SUCCES action');
return {...state, posts: payload.payload}
default:
return state;
}
};
store.js
import { createStore } from 'redux';
import rootReducer from './reducers';
export default(initialState) => {
return createStore(rootReducer, initialState);
}
Product.js (pages, component)
import React, { Component } from 'react';
import ProductList from '../../components/ProductList';
import RaisedButton from 'material-ui/RaisedButton';
//import './Product.css';
class Product extends Component {
render() {
return (
<div className="Product">
<h1>ProductList Page</h1>
<RaisedButton label="Default" />
<ProductList />
</div>
);
}
}
export default Product;
The line console.log("fetchProductsWithRedux-2"); in ProductList.js has never been reached.
What's wrong? Any ideas? Thanks in advance.
seem you missed import thunk from 'redux-thunk'. You can't return a function in redux action if you dont use any middleware like 'redux-thunk'
There are a few issues with your code.
Firstly, fetchProductsWithRedux is an action, so you would need to dispatch it rather than calling it directly. As Bjoern mentioned, the way you are calling it, the function call just returns a function, which is never called.
Now, you cannot dispatch it in the current scenario, as it returns a function, rather than object. To fix that, you will have to use redux-thunk, which will allow it to dispatch a function.
You can add it to mapDispatchToProps, as you did for getProducts, but there is a shorthand for that. In your mapDispatchToProps, you can do the following:-
const mapDispatchToProps = { fetchProductsWithRedux, getProducts }
You will notice that it is just returning an object with 2 functions.
From the documentation:
If an object is passed, each function inside it is assumed to be a Redux action creator. An object with the same function names, but with every action creator wrapped into a dispatch call so they may be invoked directly, will be merged into the component’s props.
So, it will do exactly what you did earlier with bindActionCreators, but it looks more elegant. Now, instead of onClick={this.props.action.getProducts}, you can do onClick={this.props.getProducts}. Notice the missing action.
Also, your import will change to
import { getProducts } from '../actions/product';
Now, to fix your issue, in componentDidMount, rather than calling the function directly, you will have to do:-
componentDidMount() {
this.props.fetchProductsWithRedux();
}
Hopefully, this will help.
function fetchProductsWithRedux() {
console.log("fetchProductsWithRedux-1");
return (dispatch) => {
console.log("fetchProductsWithRedux-2");
...
}
This returns a function function(dispatch){...}, which is not called in
componentDidMount() {
fetchProductsWithRedux();
}

Redux does not redraw if store value is changed

Click the login button
Auth's action is called
Reducer called
Connect mapDispatchToProps is called
However, it is not redrawn
I am in trouble because the render method of React.Component 5 is not called and redrawing is not executed.
After reading this article, I think that using Render.Component's Object.assign should call Render of React.Component.
But it does not work.
Where is wrong?
app.js
import { connect } from 'react-redux'
import App from '../components/app'
function mapStateToProps(state){
return {login: state.login}
}
function mapDispatchToProps(dispatch) {
return {
dispatch
};
}
export default connect(mapStateToProps,mapDispatchToProps)(App);
components/app.js
import React from 'react'
import { Link } from 'react-router'
import { auth } from '../actions/auth'
export default class App extends React.Component {
render() {
const { dispatch } = this.props;
return (
<div className="columns is-gapless">
<div className="column is-10 content">
<div className="content-body">
<div className="has-text-right">
{(this.props.login)?"TRUE":"FALSE"}
<button className="button is-primary" onClick={()=>dispatch(auth("test#test.com","aaaa"))}>login</button>
</div>
</div>
</div>
</div>
);
}
}
actions/auth.js
import {constant} from './constant';
export function auth(email,password) {
return {
type: constant.ACTION.AUTH,
email: email,
password:password
}
}
reducer
import {constant} from './actions/constant';
const initialState = {
login: false
};
export default function reducersIndex(state = initialState, action) {
console.log("reducers");
if (typeof state === 'undefined') {
return 0
}
switch (action.type) {
case constant.ACTION.AUTH:
return Object.assign({}, state,{
login:!state.login
});
default:
return state
}
}
Your state contains the property login, which is set in your reducer. In your component, you are also checking this.props.login.
However, in mapStateToProps, you are mapping state.state to the prop state, leaving this.props.login === undefined. For this reason, {(this.props.login)?"TRUE":"FALSE"} will always evaluate to "FALSE".
To resolve this, map login from your state to the prop login in your container:
function mapStateToProps(state){
return {login: state.login}
}

React Redux - this.props.actions.fetchPosts is not a function

i have issue with calling async action from my component, i think i did everything what was needed to work but seems like not, i used:
mapDispatchToProps
and inside i return
actions: bindActionCreators(fetchPosts, dispatch)
and i connect it.
After all these things, i try to call this action in my component -
this.props.actions.fetchPosts()
in result i get this error in console -
this.props.actions.fetchPosts is not a function
And i can not understand what's the problem with it as i did everything, here will be the full source:
Component
import React, { Component } from 'react';
import { Link } from 'react-router';
import styles from './Home.css';
import { fetchPosts } from '../actions/counter';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
class Home extends Component {
constructor(props) {
super(props)
}
render() {
return (
<div>
<div className="container">
<div className="banner_animated">
<p> dadasda</p>
</div>
</div>
<div className="container-fluid">
<div className="center">
<input type="text"/>
<button className="btn-2 btn-2a btn" onClick={this.props.actions.fetchPosts()}>Button</button>
</div>
</div>
</div>
);
}
}
function mapStateToProps(state) {
return state
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(fetchPosts, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Home);
Action
import { FETCHING_WIN_RATES, FETCHED_WIN_RATES } from '../const';
import { firebaseDb } from './firebase';
const ref = firebaseDb.ref("win_rate");
function fetchingWinRates() {
return {
type: FETCHING_WIN_RATES
};
}
function fetchedWinRates(winRates) {
return {
type: FETCHED_WIN_RATES,
winRates
};
}
// win rate champions
export function fetchPosts() {
return dispatch => {
dispatch(fetchingWinRates());
ref.on("value", function(snapshot) {
dispatch(fetchedWinRates(snapshot));
console.log(snapshot.val());
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
}
}
Write if you need some more files to help me, thank you.
If you pass a function to bindActionCreators, it will return a function. See the documentation for bindActionCreators here (in the Returns section): http://redux.js.org/docs/api/bindActionCreators.html.
You are effectively assigning this.props.action = fetchPosts here, meaning you would call fetchPosts like so: this.props.action().
If you want to access via this.props.actions.fetchPosts, you need to do the following:
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({ fetchPosts }, dispatch)
};
}
Notice the shorthand { fetchPosts } which is the same as { fetchPosts: fetchPosts }.
You don't need to use bindActionCreators http://redux.js.org/docs/api/bindActionCreators.html
const mapDispatchToProps = dispatch => ({
onClick: () => dispatch(fetchPosts(id))
})
}
and then access via this.props.onClick

Resources