Component is not updating (react-redux) - javascript

i'm another guy with the same question; Sorry, but I could not see yet my error.I'm suspecting is something about mutation, but I tried (almost) everything, getting mad. My component is not updating when I add stuff to my store, it seems is rendering just for once (first time)
I was trying with lifecycles but nothing
ACTION
export default async function getJoke() {
let jk = await axios.get('https://jokeapi.p.rapidapi.com/category/any' ,{ headers :{
'x-rapidapi-host' : 'jokeapi.p.rapidapi.com',
'x-rapidapi-key' : "***********************" }} );
let joke;
if(jk.data.type === 'single') {
joke = jk.data.joke
} else {
joke = { setup : jk.data.setup,
delivery : jk.data.delivery}
}
let getjoke = {
type : 'GETJOKE',
joke
}
store.dispatch(getjoke) ;
}
REDUCER
let initialState = { jokes : [ ] };
function joke (state = initialState, action) {
switch (action.type) {
case 'GETJOKE' : return {...state,
jokes :[...state.jokes, {jokes: action.joke}]
} ;
default : return state;
}
}
export default joke;
REDUCER-INDEX
import { combineReducers } from 'redux';
import joke from './joke'
export default combineReducers ({
joke
})
STORE
import { createStore } from 'redux';
import Combined from './reducer';
export default createStore(Combined);
COMPONENT
import React from 'react';
import BotJoke from './btnJoke';
import {connect} from 'react-redux';
import store from '../store'
class joke extends React.Component {
constructor(props) {
super(props);
this.state = {
jokes : props.jokes
}
console.log('MENDA',this.state.jokes);
}
componentDidMount() {
console.log('willdisssd receive props');
/* this.setState({jokes : [...this.state.jokes, nextProps]})
*/
}
componentWillMount(){
console.log('will mount',this.state.jokes);
console.log('Entra');
console.log('NEXT PROPS');
}
render() {
return (
<div>
<BotJoke/>
{ this.state.jokes !== undefined ? <h1>Hay bromas</h1>: <h1>NO HAY BROMAS</h1> }
</div>
)
} }
function mapStateToProps (state) {
console.log('STorE', store.getState());
return {
jokes : state.jokes
}
}
let connection = connect(mapStateToProps)(joke);
export default connection;

What you are doing is an anti pattern, using the props to setState though you can just use props directly instead.
Use this.props.jokes everywhere in your component, it should work. Let me know.
EDIT:
Assuming you want the jokes to be an array:
REDUCER
let initialState = { jokes : [ ] };
function joke (state = initialState, action) {
switch (action.type) {
case 'GETJOKE' : return {...state,
jokes :[...state.jokes, action.joke]
} ;
default : return state;
}
}
export default joke;
REDUCER-INDEX
import { combineReducers } from 'redux';
import joke from './joke'
export default combineReducers ({
joke
})
STORE
import { createStore } from 'redux';
import Combined from './reducer';
export default createStore(Combined);
COMPONENT
import React from 'react';
import BotJoke from './btnJoke';
import {connect} from 'react-redux';
import store from '../store'
const joke = (props) => {
const length = props.jokes.length
return (
<div>
<BotJoke/>
{ length !== 0 ? <h1>{JSON.stringify(props.jokes[length-1])}</h1>: <h1>NO HAY BROMAS</h1> }
</div>
)
}
function mapStateToProps (state) {
console.log('STorE', store.getState());
return {
jokes : state.jokes
}
}
let connection = connect(mapStateToProps)(joke);
export default connection;

Related

Props returning undefined when using redux store

I have started learning react-redux and was trying out the same but somehow the props are getting returned as undefined after mapping. Sharing code flow:
Below is the detailed code giving a brief idea on each component used.
App.js:
import './App.css';
import CakeContainer from './redux/cakes/CakeContainer';
import React from 'react';
import { Provider } from 'react-redux';
import store from './redux/store';
function App() {
console.log(store.getState())
return (
<Provider store = {store}>
<div className="App">
<CakeContainer/>
</div>
</Provider>
);
}
export default App;
CakeContainer.js
import React from 'react'
import { connect } from 'react-redux'
import { buyCake } from './CakeAction'
function CakeContainer(props) {
return (
<div>
<h1>Cake Container !!</h1>
<h2>Number of cakes - {props.cake}</h2>
<button onClick = {props.buyCake}> buy cakes</button>
</div>
)
}
const mapStateToProps = (state) =>{
return {
cake: state.cakeQuant
}
}
const mapDispatchToProps = dispatch => {
return {
buyCake: () => dispatch(buyCake())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(CakeContainer)
Action.js
import {BUY_CAKE} from './CakeTypes'
export const buyCake = () =>{
return{
type: 'BUY_CAKE'
}
}
Reducer:
Reducer where i am passing the initial state and action for further processing.
import { BUY_CAKE } from "./CakeTypes";
const initialState = {
cakeQunt : 10
}
const CakeReducer = (state = initialState, action)=>{
switch(action.type){
case 'BUY_CAKE': return {
...state,
cakeQunt: state.cakeQunt - 1
}
default: return state;
}
}
export default CakeReducer;
Store.js
Creating store and passing reducer details to it
[![import { createStore } from "redux";
import CakeReducer from './cakes/CakeReducer'
const store = createStore(CakeReducer,window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())
console.log(store.getState())
export default store;][1]][1]
Image showing the props value as undefined:
[1]: https://i.stack.imgur.com/EjXU1.png

Unable to access Redux array state from component

I'm trying to access my Redux groceries array from my grocery list component, and when I try to access the state with this.props.groceries, it returns 'undefined'. I'm still trying to wrap my head around some Redux concepts, but I think I'm really close. In my store.js, I'm logging
store.subscribe(() => {
console.log('store changed', store.getState());
});
And getState() is displaying my correct groceries array, with all the groceries inside it. I'm just not sure how to access this state from my groceries list component. Thanks!
Overview of my GroceryList component:
import { connect } from "react-redux";
import { bindActionCreators, createStore } from 'redux';
import * as groceryActions from '../../redux/actions/grocery-actions';
class GroceryList extends Component {
constructor(props) {
super(props);
this.state = {
};
}
addGroceryToList() {
this.props.addGrocery(newGroceryItem);
console.log(this.props.groceries); //Logs undefined
}
render() {
return(
//something
)
}
}
const mapStateToProps = (state) => ({
groceries: state.groceries.groceries
});
const mapDispatchToProps = dispatch =>
bindActionCreators(
{ addGrocery: groceryActions.addGrocery, },
dispatch
)
export default connect(mapStateToProps, mapDispatchToProps)(GroceryList);
Grocery action:
let groceryIndex = 0;
export const addGrocery = grocery => dispatch => {
dispatch({
type: 'ADD_GROCERY',
id: groceryIndex++,
grocery
});
};
Grocery reducer:
export const groceries = (state = [], action) => {
switch (action.type) {
case "ADD_GROCERY":
return [
...state,
grocery(action.grocery, action),
];
default:
return state
}
}
export const grocery = (state, action) => {
switch (action.type) {
case "ADD_GROCERY":
return {
id: action.id,
grocery: action.grocery,
};
default:
return state
}
}
Reducer combiner:
import { combineReducers } from 'redux';
import { groceries } from './grocery-reducer';
const reducer = combineReducers({
groceries: groceries,
});
export default reducer;
Store
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducers';
if (typeof window === 'undefined') {
global.window = {}
}
const enhancer = compose(
applyMiddleware(thunk),
window.__REDUX_DEVTOOLS_EXTENSION__
? window.__REDUX_DEVTOOLS_EXTENSION__()
: f => f
);
/* eslint-disable no-underscore-dangle */
const store = createStore(
reducer,
{}, // initial state
enhancer
)
store.subscribe(() => {
console.log('store changed', store.getState());
});
/* eslint-enable */
export default store
App.js
import { Provider, connect } from 'react-redux';
import { bindActionCreators } from "redux";
import * as groceryActions from "./src/redux/actions/grocery-actions";
import store from './src/redux/store';
class App extends React.Component {
state = {
};
render() {
return (
<Provider store={store}>
<Layout />
</Provider>
);
}
}
export default (App);

Async API Call, Redux React-Native

I have recently started to learn React-Native and I am trying to implement Redux to manage the state of my app.
As I have experience with React JS I implemented the state manage Redux the same way I would usually do with React JS. Everything seems to work except the async api call. The props in store change but it does not change in component props.
Here is how I set my redux store
import { createStore, compose, applyMiddleware } from 'redux';
import logger from 'redux-logger';
import thunk from 'redux-thunk';
import reducer from './reducers';
//create initial state
const initialState = {};
//create a variable that holds all the middleware
const middleware = [thunk, logger];
//create the store
const store = createStore(
reducer,
initialState,
compose(
applyMiddleware(...middleware)
)
);
export default store;
My reducer component
import { FETCH_REQUEST_BEGIN, FETCH_REQUEST_FAILED, DATA_FETCHED} from '../constants';
const initialState = {
movieResults: null,
fetching : false,
failed : false
}
export default (state = initialState, actions)=>{
switch(actions.type){
case FETCH_REQUEST_BEGIN:
return {
...state,
fetching : true
};
case DATA_FETCHED :
return {
...state,
movieResults : actions.payload,
fetchin : false
}
case FETCH_REQUEST_FAILED:
return {
...state,
failed : true
};
default :
return state;
}
}
This is the root reducer
import { combineReducers } from 'redux';
import movieReducer from './movieReducer';
export default combineReducers({
movie : movieReducer
});
action component
import axios from 'axios';
import { FETCH_REQUEST_BEGIN, FETCH_REQUEST_FAILED } from '../constants';
const apiRequest = (url, type) => {
return dispatch => {
dispatch({
type : FETCH_REQUEST_BEGIN
});
axios.get(url)
.then((results) => {
dispatch({
type : type,
payload : results.data
});
}).catch((error) => {
dispatch({
type : FETCH_REQUEST_FAILED,
payload : error
});
});
}
}
export default apiRequest;
Main component
import React, { Component } from 'react';
import { View, Text, Button, ActivityIndicator } from 'react-native';
import { API, DATA_FETCHED } from '../constants';
import { apiRequest } from '../actions';
import { connect } from 'react-redux';
class Home extends Component {
componentWillMount() {
const discoverUrlMovies =`https://jsonplaceholder.typicode.com/posts`;
this.fetchData(discoverUrlMovies, DATA_FETCHED);
}
fetchData = (url, type) => {
this.props.apiRequest(url, type);
}
shouldComponentUpdate(nextProps, prevProps){
return nextProps != prevProps
}
render() {
const { movie } = this.props;
//console out the props
console.log('this.props', this.props);
let displayMovies;
if(movie === undefined || movie === null ){
displayMovies = <ActivityIndicator size = 'large' color = '#121222'/>
}else {
displayMovies = <Text>Working</Text>
}
return (
<View style = {{flex: 1}}>
<Text>Home</Text>
{
//display result
displayMovies
}
</View>
);
}
}
const mapStateToProps = (state) => {
return {
movie : state.movieResults
}
}
export default connect(mapStateToProps, { apiRequest })(Home);
What am I missing / doing wrong?
You need to define your mapStateToProps func as
movie : state.movie.movieResults
since you're combining them as
export default combineReducers({
movie : movieReducer
});

Can´t access props after using CombineReducer

My previous React-Redux implementation was working, but after I tried to implement the combineReducer function with seperated files, an error is thrown that I don´t really understand. Hope some of you can help me!
ERROR: Uncaught TypeError: this.props.todos.map is not a function
My Reference for that Code was the Async Example of the Redux-Doc´s. But I stated with another example and the change from each examples are not documented in the doc´s.
The first code I will show, is that I had (working):
MyStore
import { createStore, applyMiddleware } from 'redux'
import thunkMiddleware from 'redux-thunk'
import createLogger from 'redux-logger'
import addItem from '../reducers/addItem'
export default function configureStore(preloadedState) {
const store = createStore(
addItem,
preloadedState,
applyMiddleware(thunkMiddleware, createLogger())
)
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers', () => {
const nextRootReducer = require('../reducers').default
store.replaceReducer(nextRootReducer)
})
}
return store
}
My Reducer
export default (state = ['Test'], action) => {
switch (action.type){
case 'ADD_ITEM':
//return action.item
return [
...state,
{
id: action.id,
text: action.item
}
]
default:
return state
}
}
Actions
export default function addItem(item){
console.log("addTOdo")
return {
type: 'ADD_ITEM',
id: nextTodoId++,
item
}
}
And the subComponent where the input is finally rendered
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
export default class TodoList extends Component {
render() {
const posts = this.props
const isEmpty = posts.length === 0
return (
<div>
<h3>Meine Aufgaben</h3>
<ul>
{isEmpty
? <h3>Sie haben noch keinen Todo´s angelegt</h3>
: <h3>Ihre Ergebnisse</h3>
}
{this.props.todos.map((todo, i) => <li key={i}>{todo.text} </li>)}
</ul>
</div>
)
}
}
const mapStateToProp = state => ({todos: state})
export default connect (mapStateToProp)(TodoList)
What I have change:
First, I created another Reducers File, called Index where I imported the addItem Reducer and exported the rootReducer:
import {combineReducers} from 'redux'
import addItem from './addItem'
import getItem from './getItem'
const rootReducer = combineReducers({
addItem,
getItem
})
export default rootReducer
After that, I changed the Store to import the rootReducer and put it´s reference in the Store (just the changes to configureStore):
import rootReducer from '../reducers/index'
const store = createStore(
rootReducer,
preloadedState,
applyMiddleware(thunkMiddleware, createLogger())
)
I don´t know if that Information is also required, but here is my Container Component:
import React, { Component, PropTypes } from 'react'
import AddTodo from '../components/AddTodo'
import TodoList from '../components/TodoList'
import { connect } from 'react-redux'
import addItem from '../actions/addItem'
import getItems from '../actions/getItems'
class App extends Component {
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this)
this.state = {text: ''}
}
handleClick(e){
console.log(e);
const {dispatch} = this.props
dispatch(addItem(e));
}
componentDidMount(){
console.log("COMPONENT MOUNT");
const {dispatch} = this.props
// dispatch(getItems())
}
componentWillReceiveProps(nextProps) {
console.log("GETTT IT");
console.log(nextProps)
}
render() {
return (
<div>
< h1 > Hallo </h1>
<AddTodo handleAddItem={this.handleClick}/>
<TodoList/>
</div>
)
}
}
App.propTypes = {
dispatch: PropTypes.func.isRequired
}
function mapStateToProps(state){
return {
AddTodo
}
}
export default connect (mapStateToProps)(App)
I hope this issue is not to basic and someone can help me. Thanks in advance!
If you inspect your redux state you will see that the following code sets up 2 more keys in the state (addItem and getItem):
const rootReducer = combineReducers({
addItem,
getItem
})
So, now to connect todos you need to one of the 2 new keys. If todos is not defined on those, then you need to add the reducer of todos to the combineReducers call.
So this needs to map to a valid location in state:
const mapStateToProp = state => ({todos: state})

React Redux- My action creator is not passing actions to reducer (sync)

When I click the DIV in Home container, I have confirmed the set function is called (I see the console log)
teamReducer function is never called. Maybe bindActionCreators should be used differently? How can i have my action creator send action to reducer to update the league store?
// teamReducer.js
export function teamReducer(state = initialState, action){
switch (action.type) {
case 'SET_TEAM':
return {
...state,
called: true
};
default:
return state;
}
};
// reducers/index.js
import { combineReducers } from 'redux';
import { routeReducer } from 'redux-simple-router';
import { teamReducer } from './teamReducer';
const rootReducer = combineReducers({
routing: routeReducer,
league: teamReducer,
});
export default rootReducer;
// actions/setTeam.js
export function setTeam(team, position) {
console.log(team, position);
return {
type: 'SET_TEAM',
team,
position
};
}
}
// Home.js
import React, { PropTypes, Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import {setTeam } from '../../actions/teams';
const mapStateToProps = ({league}) => {
return {
called: league.called
};
};
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
setTeam,
}, dispatch);
};
#connect(mapStateToProps, mapDispatchToProps)
export class Home extends Component {
constructor(props) {
super(props);
}
render() {
const {set} = this.props.setTeam
return <div onClick={set} />
}
}
The issue in the render function. You use destructuring assignment wrong.
render() {
const {set} = this.props.setTeam;
return <div onClick={set} />
}
This assignment is the same as in the following code:
const set = this.props.setTeam.set;
But setTeam is a function and doesn't have set property. The correct code is:
render() {
const {setTeam} = this.props;
return <div onClick={setTeam} />
}

Categories