items not getting added in cart using react-redux - javascript

I want to add items to the cart using redux, its not getting added neither its showing any error.
please help me out. Below is my code
this is cartItem.js
export const ADD_TO_CART = 'ADD_TO_CART'
export const REMOVE_FROM_CART = 'REMOVE_FROM_CART'
const initialState = []
const cartItemsReducer = (state = initialState, action) => {
switch (action.type) {
case ADD_TO_CART:
return [...state, action.payload]
case REMOVE_FROM_CART:
return state.filter(cartItem => cartItem.id !== action.payload.id)
}
return state
}
export default cartItemsReducer
this is store.js
import { createStore } from 'redux'
import cartItemsReducer from './CartItem'
const store = createStore(cartItemsReducer)
export default store
this is App.js
import React from 'react'
import MainStackNavigator from './src/navigation/AppNavigator'
import { Provider as StoreProvider } from 'react-redux'
import store from './src/redux/Store'
export default function App() {
return (
<StoreProvider store={store}>
<MainStackNavigator />
</StoreProvider>
)
}
this is screen where I am dispatching
import ADD_TO_CART from '../redux/CartItem'
import { useDispatch } from 'react-redux'
const dispatch = useDispatch()
const addItemToCart = item => dispatch({ type: ADD_TO_CART, payload: item })
<TouchableOpacity onPress={() => addItemToCart(item)} style={styles.button}>
<Text style={styles.buttonText}>Add +</Text>
</TouchableOpacity>

You're invoking the function with an item parameter, but where is it coming from?
You must define the parameter and then pass it.
<TouchableOpacity onPress={(item) => addItemToCart(item)} style=
{styles.button}>

Related

Fetch an API using Redux without the toolkit

I'm currently having trouble fetching an API using redux while displaying it a FlatList.
This is my actions code:
import { GET_API } from "../actionTypes";
import * as React from 'react';
const url = "https://data.binance.com/api/v3/ticker/24hr"
export const getAPI = () => {
React.useEffect(() => {
fetch(URL)
.then (x => x.json())
.then(json => {
return {
type: GET_API,
payload: {
title: json
}
}
})
}, [])
}
Here is my reducer code:
import { GET_API } from '../actionTypes/index';
var initialState = {
tasks: [],
};
export default function (state = initialState, action) {
if (action.type == GET_API) {
return {
...state,
tasks: [...state.tasks, { title: action.payload.title }]
}
}
return state;
}
And this is my ApiFetch code:
import { connect } from 'react-redux';
import {
View,
Text,
Button,
TextInput,
FlatList,
ScrollView
} from 'react-native';
import { useState } from 'react';
import { getAPI } from '../redux/actions/index';
const mapStateToProps = (state) => {
return { tasks: state.reducer.tasks };
};
const mapDispatchToProps = { getAPI };
function App({ tasks, get_API }) {
return (
<ScrollView>
<FlatList
data={tasks}
renderItem={({ item }) => (
<View>
<Text>{item.symbol}</Text>
</View>
)}
/>
</ScrollView>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
The way I learned is using a useState so I believe putting it in my actions is wrong but even without the useState it's still not displaying.
React.useEffect is a React hook, so it's only validly called in a React function component or custom React hook. If you are using "legacy redux", i.e. not the newer, better, and current redux-toolkit, then you'll need to ensure you have setup/configured your Redux store to include the Thunk middleware.
See Configuring the Store for how to install and apply the Thunk middleware.
import { createStore, applyMiddleware } from 'redux'
import thunkMiddleware from 'redux-thunk'
import { composeWithDevTools } from 'redux-devtools-extension'
import rootReducer from './reducer'
const composedEnhancer = composeWithDevTools(applyMiddleware(thunkMiddleware))
// The store now has the ability to accept thunk functions in `dispatch`
const store = createStore(rootReducer, composedEnhancer)
export default store
getApi needs to be converted to a thunk, i.e. an asynchronous action. These are typically functions that return a thunk function that is passed both a dispatch and getState function. These are so the thunk can access current state, if necessary, and dispatch further actions to the store.
export const getApi = () => async (dispatch) => {
const response = await fetch(URL);
const title = await response.json();
dispatch({
type: GET_API,
payload: { title },
);
return title;
};
Dispatch the getApi action when the component mounts via a useEffect hook call.
import { useEffect } from 'react';
import { connect } from 'react-redux';
import {
View,
Text,
Button,
TextInput,
FlatList,
ScrollView
} from 'react-native';
import { getApi } from '../redux/actions/index';
function App({ tasks, getApi }) {
useEffect(() => {
getApi();
}, []);
return (
<ScrollView>
<FlatList
data={tasks}
renderItem={({ item }) => (
<View>
<Text>{item.symbol}</Text>
</View>
)}
/>
</ScrollView>
);
}
const mapStateToProps = (state) => ({
tasks: state.reducer.tasks,
});
const mapDispatchToProps = {
getApi,
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
The connect Higher Order Component has fallen a bit out of favor. It's preferable to use the useDispatch and useSelector hooks in modern React-Redux code.
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
View,
Text,
Button,
TextInput,
FlatList,
ScrollView
} from 'react-native';
import { getApi } from '../redux/actions/index';
function App() {
const dispatch = useDispatch();
const tasks = useSelector(state => state.reducer.tasks);
useEffect(() => {
dispatch(getApi());
}, []);
return (
<ScrollView>
<FlatList
data={tasks}
renderItem={({ item }) => (
<View>
<Text>{item.symbol}</Text>
</View>
)}
/>
</ScrollView>
);
}
export default App;
Given all this, it is highly recommended to update and start using redux-toolkit. If you are already familiar with Redux/React-Redux then it'll likely be a 10-15 integration and all the current/existing reducers and actions will continue to work. What this will allow you to do is to write modern React-Redux which is much less boiler-platey, also already has thunk middleware included and active by default so asynchronous actions will work right out of the box, and allows you to write mutable reducer updates.
For example, the above tasks state & reducer function, and getApi action using RTK:
import { createSlice, createAsyncThunk } from '#reduxjs/toolkit';
const initialState = {
tasks: [],
};
export const getApi = createAsyncThunk(
"tasks/getApi",
async (_, { dispatch }) => {
const response = await fetch(URL);
const title = await response.json();
return title;
}
);
const tasksSlice = createSlice({
name: "tasks",
initialState,
extraReducers: builder => {
builder.addCase(getApi.fulfilled, (state, action) => {
const { title } = action.payload;
state.push({ title });
});
};
});
export default tasksSlice.reducer;

React Native 0.64.2, React-Redux 7.2.4, cannot get props to work "undefined is not an object"

I am trying to get React-Redux to work in my new React-Native app and am not succeeding. In my attempts to find online help, all of the examples are using Classes for each Component/Screen, but the beginning React Native template app is no longer using Classes. Everything is defined using "const" and the main App function is defined as:
`const App: () => Node = () => {...`
which are all new to me and I'm not sure if it has anything to do with my failures.
I have several Components/Screens all working nicely and do not have errors until I try to implement Redux.
Reducer:
const initState = {
syncedDate: '01/02/2022'
}
const projectsReducer = (state = initState, action) => {
switch (action.type) {
case 'PJS_SET_SYNCEDDATE':
return {
...state,
syncedDate: action.syncedDate
}
break;
default:
}
return state
}
export default projectsReducer;
Action:
export const pjsSetSyncedDate = (syncedDate) => {
return {
type: 'PJS_SET_SYNCEDDATE',
syncedDate
}
}
Store:
import { createStore, combineReducers } from 'redux';
import projectsReducer from '../reducers/projects';
const rootReducer = combineReducers({
projects: projectsReducer
});
const configureStore = () => {
return createStore(rootReducer);
};
export default configureStore;
App:
...
const store = configureStore();
...
const App: () => Node = () => {
const isDarkMode = useColorScheme() === 'dark';
const backgroundStyle = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
};
return (
<Provider store={store}>
<NavigationContainer>
<Tab.Navigator
...
</Tab.Navigator>
</NavigationContainer>
</Provider>
);
};
...
Component:
import React from 'react';
import type { Node } from 'react';
import {
Text,
View,
} from 'react-native';
import { connect } from 'react-redux';
export const DetailsScreen = ({ route, navigation }) => {
const { name } = route.params;
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Details List</Text>
<Text>Incoming param: {JSON.stringify(name)}</Text>
<Text>SyncedDate: {this.props.syncedDate}</Text>
</View>
);
};
const mapStateToProps = (state) => {
return {
syncedDate: state.projects.syncedDate
}
};
export default ConnectedDetailsScreen = connect(mapStateToProps)(DetailsScreen);
The error occurs in the Text block
"this.props.syncedDate" - undefined is not an object
You are mixing some old implementation with the new one. try to change their step by step:
As a best practice, use payload property to pass your data through your action, so add it in your action.js:
export const pjsSetSyncedDate = (syncedDate) => {
return {
type: 'PJS_SET_SYNCEDDATE',
payload: syncedDate // -----> added here
}
}
So, change your reducer to get new syncedData with payload:
const initState = {
syncedDate: '01/02/2022'
}
const projectsReducer = (state = initState, action) => {
switch (action.type) {
case 'PJS_SET_SYNCEDDATE':
return {
...state,
syncedDate: action.payload.syncedDate // -------> add payload here
}
// break;
default:
}
return state
}
export default projectsReducer;
Note: you don't need the break expression in the switch/case since you returning the result in the case. I commented out this line in the above reducer code.
Now, back to the component DetailsScreen:
import React from 'react';
import { Text,View } from 'react-native';
import { useSelector } from 'react-redux'; // -----> import useSelector instead of connect method
export const DetailsScreen = ({ route, navigation }) => {
const { name } = route.params;
const syncedData = useSelector(state => state.projects.syncedData)
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Details List</Text>
<Text>Incoming param: {JSON.stringify(name)}</Text>
<Text>SyncedDate: {syncedDate}</Text>
</View>
);
};
export default DetailsScreen;
Note: useSelector hook will get the state with a selector function. you define your reducer as projects in the combineReducers so your syncedData is in your state.projects
Note: with the above procedure, you don't need to connect your DetailsScreen to the store to get the state. useSelector hook will do that.

Unable to dispatch state values from redux store

I am new to react and redux and trying to dispatch states from store but unable to do so,
Please anyone help me to resolve the problem...
App.js
import React from "react";
import store from './reduxStore/store';
import { Provider } from 'react-redux';
import Sidebar from './Sidebar';
function App() {
return (
<div>
<Provider store={store}>
<Sidebar ></Sidebar>
</Provider>
</div>
);
}
export default (App);
This is my sidebar.js Component
import React, { useEffect } from 'react';
import { updatePageLinkActions } from "../../reduxStore/actions/updatePageLinkActions";
import { connect } from "react-redux";
const Sidebar = () =>{
useEffect(() => {
return updatePageLinkActions
}, [])
return (
<>
<ListItem button onClick={updatePageLinkActions}>
<ListItemIcon><Home></Home></ListItemIcon>
<ListItemText primary="Dashboard" />
</ListItem>
<ListItem button onClick={() => handleOpenPage("contact")}>
<ListItemIcon><AcUnit></AcUnit></ListItemIcon>
<ListItemText primary="Contact" />
</ListItem>
</>
)
}
const mapStateToProps = (state) => ({
updatePage: state.updatePage.pgLink
})
export default connect(mapStateToProps, { updatePageLinkActions })(SidebarItems);
Store Store.js
import { createStore, applyMiddleware, compose } from "redux";
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const initialState = {};
const middleWare = [thunk]
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleWare),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
)
)
export default store;
Root Reducer rootReducer.js
import { combineReducers } from 'redux';
import updatePageLinkReducer from './updatePageLinRreducer';
export default combineReducers({
updatePage: updatePageLinkReducer
});
Action updatePageLinkActions.js
import { UPDATE_PAGE_LINK } from "../actionTypes";
//import store from "../store";
export const updatePageLinkActions = dispatch => {
console.log("actions log ", dispatch.payload)
return dispatch({
type: UPDATE_PAGE_LINK,
payload: {pageLink : "Action_pageLink" }
})
};
Reducer updatePageLinkReducer.js
import { UPDATE_PAGE_LINK } from '../actionTypes';
const initialState = {
pgLink: []
};
// eslint-disable-next-line import/no-anonymous-default-export
export default function(state = initialState, action) {
switch (action.type) {
case UPDATE_PAGE_LINK:
console.log("Action called ")
return { ...state, pgLink: action.payload }
default:
return state;
}
}
I am unable to dispatch values from store,
Please somebody help me...
If you are using functional components I strongly recommend getting rid of using connect.
To get state from Redux store, you can use useSelector hook, and to dispatch an action, you can use useDispatch hook.
import { useDispatch, useSelector } from 'react-redux'
...
const dispatch = useDispatch()
const updatePage = useSelector(state => state.updatePage.pgLink)
const updatePageLinkActions = () => {
dispatch({
type: UPDATE_PAGE_LINK,
payload: {pageLink : "Action_pageLink" }
})
}
...
Your action creator is not defined properly.
It should be this:
export const updatePageLinkActions = () => dispatch => {
console.log("actions log ", dispatch.payload)
return dispatch({
type: UPDATE_PAGE_LINK,
payload: {pageLink : "Action_pageLink" }
})
};

react redux action not calling reducer

I cant for the life of my get one of my actions to call the reducer.
I've written multiple other actions and reducers in this app, which works perfectly.
It is the beginning of a filter function. I have a text input field, where I constantly keep track of the input field state, and dispatch the field value to the redux action. I have a console.log inside the action, which logs every keypress properly.
What I cant seem to understand, is why the reducer isn't called at each keypress. I've tried multiple console.log's inside the reducer, however none of them gets logged with keypresses.
The first console.log inside the reducer is called when I refresh the page.
if I try to log action.type instead, I get:
##redux/PROBE_UNKNOWN_ACTION1.0.i.0.0.9
If I try the same in any of the other reducers I've written in the same app, I get the appropriate type logged out.
Some code:
Filter Component:
import React, { useState } from 'react'
import { useDispatch } from 'react-redux';
import { filterAnecdotes } from '../reducers/filterReducer';
const Filter = () => {
const [value, setValue] = useState("");
const handleChange = (e) => {
setValue(e.target.value)
}
useDispatch(filterAnecdotes(value));
const style = {
marginBottom: 10
}
return (
<div style={style}>
filter <input onChange={handleChange} />
</div>
)
}
export default Filter
Reducer and action:
Here, I haven't figured out how to get the state of all anecdotes, and what to actually return. For now, I'm just trying to have it get called properly.
const filterReducer = (state = null, action) => {
// These logs only get logged on refresh.
// The action.type should be 'SEARCH', but is not.
console.log("From filterReducer")
console.log(action.type)
switch(action.type) {
case 'SEARCH':
// This is not called at all.
console.log(action.type, action.data)
return action.data;
default:
return state
}
}
export const filterAnecdotes = (filter) => {
console.log(filter);
return {
type: 'SEARCH',
data: filter
}
}
export default filterReducer;
Example of a redux file that actually works:
const reducer = (state = [], action) => {
console.log(state, action)
switch(action.type){
case 'NEW_ENTRY_NOTIFICATION':
console.log(action.type)
return [...state, action.data]
case 'NEW_VOTE_NOTIFICATION':
return [...state, action.data]
case 'HIDE_NOTIFICATION':
return []
default:
return state
}
}
export const createNewEntryNotification = (notification) => {
return {
type: 'NEW_ENTRY_NOTIFICATION',
data: notification
}
}
export const createNewVoteNotification = (notification) => {
return {
type: 'NEW_VOTE_NOTIFICATION',
data: notification
}
}
export const hideNotification = () => {
return {
type: 'HIDE_NOTIFICATION'
}
}
export default reducer
App component (should be irrelevant)
import React from 'react';
import NewEntry from './components/AnecdoteForm'
import AnecdoteList from './components/AnecdoteList'
import Notification from './components/Notification'
import Filter from './components/Filter';
const App = () => {
return (
<div>
<h2>Anecdotes</h2>
<Filter />
<Notification />
<AnecdoteList />
<NewEntry />
</div>
)
}
store (should be irrelevant)
import anecdoteReducer from './anecdoteReducer';
import notificationReducer from './notificationReducer';
import filterReducer from './filterReducer';
import { combineReducers } from 'redux'
const reducer = combineReducers({
anecdotes: anecdoteReducer,
notifications: notificationReducer,
filters: filterReducer,
});
export default reducer
index.js (should also be irrelevant)
import React from 'react'
import ReactDOM from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import App from './App'
import reducer from './reducers/store'
const store = createStore(reducer)
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
export default App
I'll be happy to provide more information if needed.
This is for a project from fullstackopen.
Try to instantiate useDispatch like this after const [value, setValue] = useState("");
const dispatch = useDispatch();
And then use the intance to dispatch the action
dispatch(filterAnecdotes(value));
the use of useDispatch is misunderstood.
Link for reference: https://react-redux.js.org/api/hooks#usedispatch
You should create a dispatch from useDispatch:
const dispatch = useDispatch();
dispatch(filterAnecdotes(value));

Redux React Native - Action not passing data to reducer

I am new to Redux and it might be some silly error. I am trying to make an Api call in Action and pass the data to the reducer. I can see the response from the api call but for some reason it's not sharing the data correctly with the reducer or I don't know how to pass and render the state properly to home.js. Please find below action - reducers - store.js - home.js
Action file
export const DATA_AVAILABLE = 'DATA_AVAILABLE';
export function getData(){
return (dispatch) => {
//Make API Call
fetch("MY API URL").then((response) => {
return response.json();
}).then((data) => {
var data = data.articles;
console.log(data)
dispatch({type: DATA_AVAILABLE, data:data});
})
};
}
REDUCERS
import { combineReducers } from 'redux';
import { DATA_AVAILABLE } from "../actions/" //Import the actions types constant we defined in our actions
let dataState = {
data: [],
loading:true
};
const dataReducer = (state = dataState, action) => {
switch (action.type) {
case DATA_AVAILABLE:
state = Object.assign({}, state, { data: action.data, loading:false });
console.log(dataState)
return state;
default:
return state;
}
};
// Combine all the reducers
const rootReducer = combineReducers({
dataReducer
// ,[ANOTHER REDUCER], [ANOTHER REDUCER] ....
})
export default rootReducer;
STORE.JS
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducers from '../app/reducers/index'; //Import the reducer
// Connect our store to the reducers
export default createStore(reducers, applyMiddleware(thunk));
HOME.JS
'use strict';
import React, { Component } from 'react';
import {
StyleSheet,
FlatList,
View,
Text,
ActivityIndicator
} from 'react-native';
import {bindActionCreators} from 'redux';
import { connect } from 'react-redux';
import * as Actions from '../actions'; //Import your actions
class Home extends Component {
constructor(props) {
super(props);
this.state = {
};
this.renderItem = this.renderItem.bind(this);
}
componentDidMount() {
this.props.getData(); //call our action
}
render() {
if (this.props.loading) {
return (
<View style={styles.activityIndicatorContainer}>
<ActivityIndicator animating={true}/>
</View>
);
} else {
console.log(this.state)
return (
<View style={{flex:1, backgroundColor: '#F5F5F5', paddingTop:20}}>
<FlatList
ref='listRef'
data={this.props.data}
renderItem={this.renderItem}
keyExtractor={(item, index) => index}/>
</View>
);
}
}
renderItem({item, index}) {
return (
<View style={styles.row}>
<Text style={styles.title}>
{this.props.data.title}
</Text>
<Text style={styles.description}>
</Text>
</View>
)
}
};
// The function takes data from the app current state,
// and insert/links it into the props of our component.
// This function makes Redux know that this component needs to be passed a piece of the state
function mapStateToProps(state, props) {
return {
loading: state.dataReducer.loading,
data: state.dataReducer.date
}
}
// Doing this merges our actions into the component’s props,
// while wrapping them in dispatch() so that they immediately dispatch an Action.
// Just by doing this, we will have access to the actions defined in out actions file (action/home.js)
function mapDispatchToProps(dispatch) {
return bindActionCreators(Actions, dispatch);
}
//Connect everything
export default connect(mapStateToProps, mapDispatchToProps)(Home);
You are not mutating the state righty.
Redux do only shallow comparison for optimisation.
Its only check reference.
Reference need to be update.
state = Object.assign({}, state, {
data: [
...state.data, //change previous state data reference
...action.data //update current state data reference
],
loading: false
});

Categories