Sharing state with 2 components Redux - javascript

Trying to share the state between 2 components so the dashboard and the displayed component can change states simultaneously. Exmp: Switch from dashboard view to application view and display application component. Problem: I can't wrap my head around what I'm missing here and why the state does not work on my dashboard component.
Redux Slice:
import { createSlice } from '#reduxjs/toolkit';
const initialState = {
selector: 0,
};
export const dashboardSlice = createSlice({
name: 'mainDashState',
initialState,
reducers: {
setSelector: (state, action) => {
state.selector = action.payload;
},
},
});
export const { setSelector } = dashboardSlice.actions;
export default dashboardSlice.reducer;
Redux Store:
import { configureStore } from "#reduxjs/toolkit";
import mainDashSlice from './slices/mainDashSlice';
export const store = configureStore({
reducer: {
mainDashState: mainDashSlice,
},
})
Dashboard.jsx:
import { React } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import '../../css/SideBar.css';
import { UilSignOutAlt } from '#iconscout/react-unicons';
import Logo from '../../../../assets/img/companyLogo.jpg';
import { SidebarData } from '../../Data/Data';
import { setSelector } from '../../../../features/redux/slices/mainDashSlice';
// import Applications from '../applicationsTab/Applications';
function SideBar() {
const selector = useSelector((state) => state.selector);
const dispatch = useDispatch();
console.log(selector);
return (
<div className="Sidebar">
{/* logo */}
<div className="logo">
<img src={Logo} alt="logo" />
<span>Company Name</span>
</div>
{/* menu */}
<div className="menu">
{SidebarData.map((item, index) => (
/* eslint-disable */
<div
role="menu"
className={selector === index ? 'menuItem active' : 'menuItem'}
key={index}
onClick={() => dispatch(setSelector(selector))}
onKeyDown={() => dispatch(setSelector(selector))}
>
<item.icon />
<span>{item.heading}</span>
</div>
))}
<div className="menuItem">
<UilSignOutAlt />
</div>
</div>
</div>
);
}
export default SideBar;
TL;DR:
When clicking on the dashboard "Application" change the state in redux for another component as well to re-render the main tab.
Thanks guys! Do need to understand what I'm doing wrong...

Related

Need help: Error: Invalid hook call. Hooks can only be called inside of the body of a function component

×
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
import './App.css';
import {useSelector} from 'react-redux';
import Header from './Header';
import Sidebar from './Sidebar';
import Feed from './Feed';
import { selectUser } from './features/userSlice';
import Login from './Login';
function App() {
const user = useSelector(selectUser)
return (
<div className="app">
<Header />
{!user ? (
<Login />
) : (
<div className="app__body">
<Sidebar />
<Feed />
{/* Widgets */}
</div>
)}
</div>
);
}
export default App;
import { createSlice } from '#reduxjs/toolkit';
export const userSlice = createSlice({
name: 'user',
initialState: {
user: null,
},
reducers: {
login: (state, action) => {
state.value = action.payload;
},
logout: (state) => {
state.user = null;
},
},
});
export const { increment, decrement, incrementByAmount } = userSlice.actions;
// Selectors
export const selectUser = (state) => state.user.user;
export default userSlice.reducer;

React Redux --> UseSelector --> Not Working

I am trying to make a simple exercise for react-redux to understand the process but somehow I am stuck .. any help would be really appreciate.
The interesting part is when I do subscribe and try to log store into the console, it works and shows me updated value but I am not able to select it using useSelector
Also with the help of Dev tool's i could see the state being changed from INIT to ADD_USER..
Below are my components files and reducers.
App.js
import React from "react";
import { Provider } from "react-redux";
import store from "./stores/store";
import { HomePage } from "./components/containers/HomePage";
function App() {
return (
<Provider store={ store }>
<HomePage/>
</Provider>
);
}
export default App;
HomePage.js. --> Here state.isLogin is not selected.. but the subscribe comment works
import React from "react";
import { Sidebar } from "./Sidebar";
import { LoginPage } from "./LoginPage";
import { useSelector } from "react-redux";
export const HomePage = () => {
const userLogin = useSelector(state => state.isLogin);
// const storeState = store.subscribe (() => console.log(store.getState()));
return (
<div>
<LoginPage />
<Sidebar />
</div>
);
};
LoginPage.js
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import * as action from "../../action/index";
export const LoginPage = (setLogin) => {
const dispatch = useDispatch();
const [name, setName] = useState("");
const createUser = (e) => {
e.preventDefault();
const addUser = {
name: name,
isLogin: true
};
dispatch(action.addUsers(addUser));
};
return (
<div className="card border-0 shadow">
<div className="card-header">Login Here!</div>
<div className="card-body">
<form onSubmit={(e) => createUser(e)}>
<div className="form-group">
<input
type="text"
className="form-control"
placeholder="Enter Your Name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
<button className="btn btn-primary" type="submit">
Create Contact
</button>
</form>
</div>
</div>
);
};
reducers - Index.js and user.js
import userReducer from './users'
import { combineReducers} from "redux";
const allReducers = combineReducers({
addUser : userReducer,
});
export default allReducers;
User.js
import * as types from '../actionTypes/index'
const intialState = {
user: [],
messages : [],
isLogin : false
};
const users = (state = intialState, action) => {
switch (action.type) {
case types.ADD_USER:
return {
...state,
user: [action.payload.name, ...state.user],
isLogin: action.payload.isLogin
};
default:
return state
}
}
export default users;
Store.js
import { createStore } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import allReducers from '../reducers'
const store = createStore(allReducers,composeWithDevTools());
export default store;
Any idea's/Input on what went wrong ? or what is the issue?
Thank you
Try using below code in HomePage
const userLogin = useSelector(state => state.addUser.isLogin);

having issues displaying objects from state

I am having an issue with getting the data from my state I need the information from the employee state to display the pages in referring to are Employee.js and EmployeeItem.js in my repo.
I can map through the state and display a number of blank objects based on how many entries are in the state but I am having trouble displaying and information for the individual objects
How the page currently renders
How I need the page to render
Employee.js
import React, {Fragment, useEffect} from 'react'
import {Link} from 'react-router-dom'
import {connect} from 'react-redux'
import Spinner from '../../layout/Spinner'
import {getEmployees} from '../../../actions/employee'
import EmployeeItem from './EmployeeItem'
import PropTypes from 'prop-types'
const Employees = ({ getEmployees, employee: {employees, loading}}) => {
useEffect(() => {
getEmployees()
}, [])
return (
<Fragment>
{loading ? <Spinner/> :
<Fragment>
<section className="content bg-light">
<h1 className="x-large text-primary title">Employees</h1>
<div className="add">
<Link to="/employees/new"><i className="fas fa-plus-circle text-primary x-large"></i></Link>
</div>
{employees.length > 0 ? (
employees.map(employee => (
<EmployeeItem key={employee._id} profile={employee} />
))
) : <h4>No Employees Found....</h4>}
</section>
</Fragment>
}
</Fragment>
)
}
Employees.propTypes = {
getEmployees: PropTypes.func.isRequired,
employee: PropTypes.object.isRequired,
}
const mapStateToProps = state => ({
employee: state.employee
})
export default connect(mapStateToProps, {getEmployees})(Employees)
EmployeeItem.js
import React from 'react'
import {Link} from 'react-router-dom'
import PropTypes from 'prop-types'
const EmployeeItem = ({employee: name, employement, _id}) => {
return (
<div className="employee-container">
<Link to={`/employees/${_id}`}>
<div className="employee-icon bg-white">
<div className="circle-sal">
<h4 className="large initials">J D</h4>
</div>
<p className="lead-2">{name}</p>
</div>
</Link>
</div>
)
}
EmployeeItem.propTypes = {
employee: PropTypes.object.isRequired,
}
export default EmployeeItem
[What is in the state:
Any help on fixing this would be much appreciated.
If you look at the EmployeeItem. You are assigning employee value to profile prop.
<EmployeeItem key={employee._id} profile={employee} />
and you are trying to access the value wrongly.
const EmployeeItem = ({employee: name, employement, _id}) => {
}
You could have done either this way
<EmployeeItem key={employee._id} profile={employee} />
and in EmployeeItem
const EmployeeItem = ({ profile: { name, _id } }) => {
}
or
<EmployeeItem key={employee._id} {...employee} />
and in EmployeeItem
const EmployeeItem = ({ name, _id }) => {
}

Error: Invalid value of type object for mergeProps argument

I'm setting up my app with redux, and i'm new to it. I want to make onClick() event to take item's id but im getting error.
I searched a lot of answers here, but they didn't help me a lot.
Documentation says, that i'm not connecting my action right, but I found no good explanation, only example with toDo, which is not enough for me.
Products.js(where I want my onClick())
import React, { Component } from "react";
import Navbar from "../navbar/Navbar";
import Product from "../lists/Product";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { getItems } from "../../actions/getItems";
import { getDetails } from "../../actions/getDetails";
class Products extends Component {
componentDidMount() {
this.props.getItems();
}
render() {
return (
<div className="container-fluid products">
<Navbar />
<div className="container">
<h1 className="title display-3 text-center pt-2">
<b>Our Products</b>
</h1>
<div className="underline" />
<div className="py-5">
<div className="container">
<div className="row">
{this.props.shopItems.items.map(item => {
return (
<div
onClick={() =>this.props.getDetails(item.id)}
className="col-lg-3 col-md-6 col-sm-6 col-xs-9"
key={item.id}
>
<div className="card-deck">
<Product
name={item.name}
brand={item.brand}
img={item.img}
price={item.price}
/>
</div>
</div>
);
})}
</div>
</div>
</div>
</div>
</div>
);
}
}
Products.propTypes = {
shopItems: PropTypes.object.isRequired,
getDetails:PropTypes.func.isRequired
};
const mapStateToProps = state => ({
shopItems: state.shopItems
});
export default connect(
mapStateToProps,
{ getItems }
)(Products);
getDetails.js
import {SHOW_DETAILS} from './types';
import {data} from '../data/data';
export const getDetails = id => dispatch =>{
const detailProduct = data.find(item => item.id === id)
dispatch({
type:SHOW_DETAILS,
payload:detailProduct
})
}
detailsReducer.js
import { SHOW_DETAILS } from "../actions/types";
const initialState = {
detailProduct: {}
};
export default (state = initialState, action) => {
switch (action.type) {
case SHOW_DETAILS:
return {
detailProduct: action.payload
};
default:
return state;
}
};
index.js(root reducer)
import {combineReducers} from 'redux'
import itemsReducer from './itemsReducer'
import detailsReducer from './detailsReducer';
export default combineReducers({
shopItems:itemsReducer,
detailProduct:detailsReducer
})
Store.js
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import rootReducer from './reducers/index';
const initialState = {};
const middleware = [thunk];
let store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
export default store;
I expect:
Connect action getDetails to component Products.js.
Make onClick() to grab needed item's id.
Use find() item by it's id, receive item's info in state detailProduct.
No errors.

Error in connecting components in redux

I get an error saying
You must pass a component to the function returned by connect.
Instead received undefined.
I don't know why this is happening. It works with my Checkout.js component, but not my Store.js component. Why is it working for Checkout but not Store? I want to have access to {total} like I do in the Checkout component.
This is my container Store.js
import { connect } from 'react-redux';
import { getItems, getCurrency, getTotal} from '../ducks/cart';
import Store from '../components/Store';
const mapStateToProps = (state, props) => {
return {
total: getTotal(state, props)
}
}
export default connect(mapStateToProps)(Store);
And this is my component Store.js
import React, {Component} from 'react';
import { PropTypes } from 'react';
import Home from '../components/Home';
import Cart from '../containers/Cart';
import ProductList from '../containers/ProductList';
import Checkout from '../containers/Checkout';
class Store extends Component{
render(){
return(
<div className="container">
<div className="row">
<div className="col-md-12">
<h3>Armor and Weapon Store</h3>
<h4 className="badge badge-warning margin-right">Gold: </h4>
</div>
</div>
<div className="row">
<div className="col-md-8">
<ProductList />
</div>
<div className="col-md-4">
<Cart />
<Checkout />
</div>
</div>
</div>
);
}
}
Store.propTypes = {
total: PropTypes.number,
}
export default Store;
Here is the container Checkout.js that works
import { connect } from 'react-redux';
import { getItems, getCurrency, getTotal} from '../ducks/cart';
import Checkout from '../components/Checkout/Checkout';
const mapStateToProps = (state, props) => {
return {
total: getTotal(state, props)
}
}
export default connect(mapStateToProps)(Checkout);
And the component Checkout.js
import React, { PropTypes } from 'react';
import {Component} from 'react';
import Home from '../components/Home.js';
class Checkout extends Component{
buttonClick = () => {
let { total } = this.props;
var home = new Home
var max = home.getMax()
console.log(total);
console.log(max);
if (max >= total) {
max = max - total;
console.log(max);
}
else {
console.log('Not enough gold!');
}
}
render() {
return(
<div>
<button type="button" onClick={this.buttonClick}> Checkout </button>
</div>
);
}
}
Checkout.propTypes = {
total: PropTypes.number,
}
export default Checkout;

Categories