Hello I have an action to get data from my backend and then I created a new container and I use this state and I created an action to filter this state, and then when it clicks back to my component product the products that were filtered
My action fetch:
export const fetchProduct = () => {
console.log('action')
return dispatch => {
dispatch(fetchStarted());
api
.get('/products')
.then(res => {
dispatch(fetchSucess(res.data));
})
.catch(err => {
dispatch(fetchFailed(err.message));
});
};
};
My reducer fetch:
const initialState = {
loading: false,
products: [],
error: null
};
export default function productReducer(state = initialState, action) {
switch (action.type) {
case FETCH_LOADING:
return {
...state,
loading: true
};
case FETCH_SUCESS:
return {
...state,
loading: false,
error: null,
...state, products: action.data
};
case FETCH_FAIL:
return {
...state,
loading: false,
error: action.error
};
default:
return state;
}
}
My container product:
class HomeProducts extends Component {
componentDidMount() {
this.props.fetchProduct();
}
render() {
const productItems = this.props.products.map( product =>(
<div className="col-md-4 pt-4 pl-2" key={product.id}>
<div className = "thumbnail text-center">
<a href={`#${product.id}`} onClick={(e)=>this.props.handleAddToCard(e,product)}>
<p>
{product.name}
</p>
</a>
</div>
<b>{util.formatCurrency(product.price)}</b>
<button className="btn btn-primary" onClick={(e)=>this.props.handleAddToCard(e,product)}>Add to Cart</button>
</div>
)
)
return (
<div className="container">
<div className="row">
{productItems}
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return{
products: state.data.products,
loading: state.data.loading,
error: state.data.error
}
};
const mapActionsToProps = {
fetchProduct: fetchProduct
};
export default connect(mapStateToProps, mapActionsToProps)(HomeProducts);
My product container will show in a div all the products it fetched in the backend.
And now My container filter:
class FilterHome extends Component {
render() {
console.log(this.props);
return (
<>
<div className="row">
<button className="filterbt btn btn-danger btn-rounded">Filters</button>
<div className=" mt-4 d-flex flex-column">
<p className="textCategory">CATEGORY</p>
<div className="category d-flex flex-column">
<p>Stat Trak</p>
<p>Normal</p>
</div>
<p className="textCategory">EXTERIOR</p>
<div className="category d-flex flex-column">
<p value={2} onChange={(e) => this.props.filterProducts(this.props.products, e.target.value)}>Factory New ()</p>
<p>Minimal Wear ()</p>
<p>Field Tested ()</p>
<p>Well Worn ()</p>
<p>Battle Scarred ()</p>
</div>
</div>
</div>
</>
)
}
}
const mapStateToProps = state => ({
products: state.data.products,
});
export default connect(mapStateToProps, {filterProducts})(FilterHome);
and then I created an action and a redux to get the filtered product list and then send this filtered stripe to my div that displays the products.
Action filter products:
import {FILTER_PRODUCT} from '../constants/fetchTypes';
export const filterProducts = (products,value) => (dispatch) => {
return dispatch({
type:FILTER_PRODUCT,
payload:{
value:value,
products:value === ''? products: products.filter(v => v.id_sub = value)
}
})
}
My reducer filter:
import {
FETCH_SUCESS,
FETCH_FAIL,
FETCH_LOADING,
FILTER_PRODUCT
} from '../constants/fetchTypes';
const initialState = {
products: []
};
export default function productReducer(state = initialState, action) {
switch (action.type) {
case FILTER_PRODUCT:
return {
...state,
filteredProducts: action.payload.products
};
default:
return state;
}
} return state;
}
}
I don't know how I can change the filtered products in my product div
Related
How to get the dispatch to recognize each product when the button is clicked?
When the HTML is mapped through the examples array, there is an index given. But when I click the button to addToCart, the elements of objects of array, it shows undefined
{type: "ADD_TO_CART", item: {…}}
item: {id: undefined, name: undefined, price: undefined, desc: undefined, type: undefined, …}
type: "ADD_TO_CART"
This is Menu.js
import React, { useState } from 'react';
import examples from './examples';
import './Menu.css';
import { useStateValue } from './StateProvider';
const Menu = ({ id, name, imgUrl, desc, price, type }) => {
const [dishes, setDishes] = useState(examples);
const [, dispatch] = useStateValue();
const addToCart = () => {
// add item to basket
dispatch({
type: 'ADD_TO_CART',
item: {
id,
name,
price,
desc,
type,
imgUrl,
},
});
};
return (
<div className='menu'>
<h1>Menu</h1>
<div className='menu__starters'>
<h1>Starters</h1>
{dishes.map((dish, index) => (
<div className='menu__column'>
<div className='menu__row'>
<div className='menu__card' key={index}>
<div className='menu__img'>
<img src={dish.imgUrl} alt='img' />
</div>
<div className='menu__desc'>
<div className='menu__name'>
<h2>{dish.name}</h2>
</div>
<div className='menu__description'>
<p>{dish.desc}</p>
</div>
<div className='menu__credentials'>
<div className='menu__price'>
<h5>Damage- ${dish.price}</h5>
</div>
<div className='menu__button'>
<button onClick={addToCart} key={index}>
Add to Cart ->
</button>
</div>
</div>
</div>
</div>
</div>
</div>
))}
</div>`
An array of objects is in another file examples.js which is exported.
This is reducer.js
export const initialState = {
cart: [],
};
function reducer(state, action) {
console.log(action);
switch (action.type) {
case 'ADD_TO_CART':
// logic for adding item to cart
return { state };
break;
case 'REMOVE_FROM_CART':
//logic for removing item from cart
return { state };
break;
default:
return state;
}
}
export default reducer;`
Blockquote
It's undefined because those variables are not defined in addToCart scope, you haven't passed any data to it.
You have to pass the dish into addToCart
<button onClick={()=>addToCart(dish)} ...>
And
const addToCart = ({ id, name, imgUrl, desc, price, type }) => {...}
I have problem with calling componentDidMount.
Situation:
I have 2 reducers. They called in different components and do not intersect. In every component in ComponentDidMount i calling function from Reducer which set data. In different ways one of two is not working and function from reducer is not called. I have error like "Cannot read property of null". After reload page working of components is changed.
First Reducer:
const SET_VIDEOS = 'SET_VIDEOS';
const TOOGLE_IS_FETCHING = 'TOOGLE_IS_FETCHING';
let initialState = {
videos: null,
isFetching: null
}
const youtubeReducer = (state = initialState, action) => {
switch(action.type){
case SET_VIDEOS: {
console.log("muerto.");
return {...state, videos: action.videos}
}
case TOOGLE_IS_FETCHING: {
return {...state, isFetching: action.isFetching}
}
default:{
return state;
}
}
}
export const setVideos = (videos) => ({
type: SET_VIDEOS, videos
});
export const setIsFetching = (isFetching) => ({
type: TOOGLE_IS_FETCHING, isFetching
});
export const getVideosThunkCreator = () => {
return(dispatch) => {
dispatch(setIsFetching(true));
console.log("ALO");
youtubeApi.getVideos().then(data => {
dispatch(setVideos(data.items));
dispatch(setIsFetching(false));
console.log(data.items);
})
}
}
Second Reducer:
let initialState = {
dj: null,
isFetching: null
}
const djReducer = (state = initialState, action) => {
switch(action.type){
case SET_DJ:{
console.log("muerto2.");
return {...state, dj: action.dj}
}
case TOOGLE_IS_FETCHING: {
return {...state, isFetching: action.isFetching}
}
default:
return state;
}
}
export const setDj = (dj) => ({
type: SET_DJ, dj
});
export const setIsFetching = (isFetching) => ({
type: TOOGLE_IS_FETCHING, isFetching
});
Container Component with First Reducer:
class LivesContainer extends React.Component{
componentDidMount(){
this.props.getVideosThunkCreator();
console.log(this.props);
}
render(){
return(
<>
{this.props.isFetching ? <Preloader/> : <Lives videos={this.props.videos}/>}
</>
);
}
}
let mapStateToProps = (state) => {
return{
videos: state.youtubeReducer.videos,
isFetching: state.youtubeReducer.isFetching
}
}
export default connect(mapStateToProps, {
getVideosThunkCreator,
setIsFetching
})(LivesContainer);
Container Component with Second Reducer:
class DjContainer extends React.Component {
componentDidMount(){
console.log("MOUNT");
let djId = this.props.match.params.djId;
if(!djId){
djId = 0;
}
let djs = this.props.djs;
this.props.setIsFetching(true);
console.log(djs);
console.log(djId);
djs.forEach(dj => {
if(dj.id == djId){
this.props.setDj(dj);
this.props.setIsFetching(false);
}
});
console.log(this.props);
}
componentWillUnmount(){
console.log("UNMAUNT");
}
render(){
return(
<>
{this.props.isFetching ? <Preloader/>:
<Dj {...this.props} dj={this.props.dj} />
}
</>
);
}
}
let mapStateToProps = (state) => ({
dj: state.djReducer.dj,
djs: state.djsReducer.djs,
isFetching: state.djReducer.isFetching
});
let WithUrlDataContainerComponent = withRouter(DjContainer);
export default connect(mapStateToProps,{
setDj,
setIsFetching
})(WithUrlDataContainerComponent);
First Component where i have errors:
const Lives = (props) => {
let bannerId;
let videoBanner = "https://www.youtube.com/embed/";
let videos = [];
props.videos.forEach((video,index) => {
if(index == 0){
bannerId = video.contentDetails.videoId;
}else{
videos.push(video);
}
});
console.log(videos);
videoBanner += bannerId;
let videosMap = videos.map((video,index) => {
return <Video video={video} key={index}/>
})
return(
<div className={classes.main}>
<div className={classes.container}>
<h1>Our videos</h1>
<div className={classes.videos}>
<iframe width="90%" height="80%" src={videoBanner} frameborder="0" allow="accelerometer; autoplay=1; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<div className={classes.videoList}>
{videosMap}
</div>
</div>
</div>
</div>
);
}
error from there:
props.videos.forEach((video,index) => {
if(index == 0){
bannerId = video.contentDetails.videoId;
}else{
videos.push(video);
}
});
From Secornd Component:
const Dj = (props) => {
console.log(props);
let video = "https://www.youtube.com/embed/" + props.dj.video;
return(
<div className={classes.main}>
<div className={classes.container}>
<h1>{props.dj.name}</h1>
<iframe width="90%" height="80%" src={video} frameborder="0" allow="accelerometer; autoplay=1; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<div className={classes.links}>
<a href={props.dj.fb} target="_blank">
<img src={fb}/>
</a>
<a href={props.dj.sound} target="_blank">
<img src={sound}/>
</a>
<a href={props.dj.inst} target="_blank">
<img src={inst}/>
</a>
</div>
</div>
</div>
);
}
Error from there:
let video = "https://www.youtube.com/embed/" + props.dj.video;
I have form where I have 2 input textboxes. On its change handler I am setting their respective values into state object. However I want to store those 2 values into redux store so that I can use it on multiple components. Is there anyway where I can store those 2 input values into state and in redux store as well. Below is my login componet code. Thanks in advance.
import React from "react";
import { connect } from "react-redux";
import * as loginAction from "../redux/actions/LoginAction";
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
username: "",//want to have this value in redux store so that I can use it in multiple components
password: "",
errorUsername: null,
errorPassword: null,
};
this.handleValidation = this.handleValidation.bind(this);
this.handleChange = this.handleChange.bind(this);
}
//assign textbox values to props
handleChange = (e) => {
this.setState({
[e.target.name]: [e.target.value],
});
};
//handle input validation
handleValidation = (event) => {
if (!this.state.username) {
this.setState({ errorUsername: "Please enter User Name" });
event.preventDefault();
}
if (!this.state.password) {
this.setState({ errorPassword: "Please enter Password" });
event.preventDefault();
}
if (this.state.password && this.state.username) {
this.setState({ errorUsername: null, errorPassword: null });
let postData = {
username: this.state.username[0],//want to have this value in redux store so that I can use it in multiple components
password: this.state.password[0],
};
event.preventDefault();
//dispatching an action
this.props.dispatch(loginAction.checkLogin(postData, this.props.history));
}
};
render() {
return (
<div className="d-flex flex-column">
<div className="d-flex globalStyle">
<div className="w-100 justify-content-start p-5">
<div className="p-10 bg-white">
<div className="Login">
<form>
<div className="d-flex flex-column">
<div>Login</div>
<div className="d-flex flex-row">
<div>
<b>User name</b>
</div>
</div>
<div>
<input
type="username"
name="username"
className="inputText"
id="exampleInputUserName"
value={this.props.userName}
onChange={this.handleChange}
placeholder="Enter User Name"
></input>
</div>
<div className="text-danger d-flex flex-row p-2 ml-2">
{this.state.errorUsername && (
<div>{this.state.errorUsername}</div>
)}
</div>
<div className="d-flex flex-row">
<div>
<b>Password</b>
</div>
</div>
<div className="d-flex flex-row p-2 ml-2">
<input
type="password"
name="password"
className="inputText"
value={this.props.password}
onChange={this.handleChange}
placeholder="Enter Password"
></input>
</div>
<div className="text-danger d-flex flex-row p-2 ml-2">
{this.state.errorPassword && (
<div>{this.state.errorPassword}</div>
)}
</div>
<div className="d-flex flex-row justify-content-around p-2 ml-2">
<button
type="submit"
onClick={this.handleValidation}
className="button-style"
>
Login
</button>
</div>
</div>
<div>
<br></br>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
userDetails: state.userDetails,
};
}
export default connect(mapStateToProps)(Login);
Mu login action code is
const getUserDetailsSuccess = (userDetails) => ({
type: "GET_DETAILS",
userDetails,
});
export const checkLogin = (loginData, history) => {
const url = `login`;
return (dispatch) => {
return service
.post(url, loginData)
.then((res) => {
const userDetails = res.data.response_message;
dispatch(getUserDetailsSuccess(userDetails));
})
.catch((error) => {
throw error;
});
};
};
My Reducer code is
function loginReducer(state = { userDetails: {} }, action) {
switch (action.type) {
case "GET_DETAILS":
return { userDetails: action.userDetails };
default:
return state;
}
}
export default loginReducer;
My code is working fine without any issue.
Just add loginData into your dispatch
const getUserDetailsSuccess = (userDetails, loginData) => ({
type: "GET_DETAILS",
userDetails,
loginData
});
export const checkLogin = (loginData, history) => {
const url = `login`;
return (dispatch) => {
return service
.post(url, loginData)
.then((res) => {
const userDetails = res.data.response_message;
dispatch(getUserDetailsSuccess(userDetails, loginData));
})
.catch((error) => {
throw error;
});
};
};
and in the reducer action.loginData will be the content you want (don't sure how you want to store it)
function loginReducer(state = { userDetails: {} }, action) {
switch (action.type) {
case "GET_DETAILS":
return { userDetails: { ...action.userDetails, ...action.loginData } };
default:
return state;
}
}
export default loginReducer;
I am stuck around a project and honestly I don't know how to solve it (I am quite new before you judge)
so this is my code:
class EditProfile extends Component {
state = {
företagsnamn: '',
organisationsnummer: '',
};
handleChange = e => {
this.setState({
[e.target.id]: e.target.value
});
};
handleSubmit = e => {
e.preventDefault();
// console.log(this.state);
this.props.editProfile(this.state);
this.props.history.push("/dash");
};
render() {
const { auth, profile } = this.props;
if (auth.isEmpty) return <Redirect to="/dash" />;
return (
<div >
<form className="white" onSubmit={this.handleSubmit}>
<div className="row">
<div className="col xl6 l6 m6 s12">
<label>Foretagsnamn:</label>
<input
type="text"
disabled
placeholder={profile.foretagsnamn}
id="foretagsnamn"
onChange={this.handleChange}
/>
</div>
<div className="col xl6 l6 m6 s12">
<label>organisationsnummer:</label>
<input
type="number"
placeholder={profile.organisationsnummer}
id="organisationsnummer"
onChange={this.onChange}
/>
</div>
</div>
<div className="input-field">
<button className="btn orange lighten-1" style={{width:'100%'}} >Submit</button>
{ }
</div>
</form>
</div>
}}
const mapStateToProps = state => {
return {
auth: state.firebase.auth,
profile: state.firebase.profile
};
};
const mapDispatchToProps = dispatch => {
return {
editProfile: profil => dispatch(editProfile(profil))
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(EditProfile);
this was the action
export const editProfile = (profil) => {
return (dispatch, getState, { getFirestore, getFirebase }) => {
const firebase = getFirebase();
const firestore = getFirestore();
const profile = getState().firebase.auth
console.log(profile)
const authorId = getState().firebase.auth.uid;
// const foretagsnamn = getFirestore().firestore.collection('users').doc(profile.uid).foretagsnamn
// firebase.auth()
firestore.collection('users').doc(profile.uid).set({
// foretagsnamn: foretagsnamn,
// organisationsnummer: profil.organisationsnummer,
adress: profil.adress,
ort: profil.ort,
telefonnummer: profil.telefonnummer,
postnummer: profil.postnummer,
}, { merge: true }
).then(() => {
dispatch({ type: 'UPDATE_SUCCESS' });
}).catch(err => {
dispatch({ type: 'UPDATE_ERROR' }, err);
});
}}
and this the reducer
const editProfileReducer = (state = initState, action) => {
switch (action.type) {
case "EDITPROFILE_ERROR":
return {
...state,
editError: action.error
};
case "EDITPROFILE_SUCCESS":
return {
...state,
user:action.user
};
default:
return state;
}
}
export default editProfileReducer;
however when I press the button submit it shows this error:
FirebaseError: Function CollectionReference.doc() requires its first argument to be of type non-empty string, but it was: undefined
PS: Solved. The action was wrong. I changed ´´´const profile = getState().firebase.auth.```**instead of profile. **
Stays open if someone needs.
I am trying to open up a Modal component on a onClick from a listItem in a listGroup component. However, the setup I currently have either causes my application to hang and I am not able to click anything on the application or the state does not get updated and the modal does not render.
Another weird that thing that occurs is when I console log to see what the showModalState is, the state changes but when I check the react developer tools to see if it changed, it's always at the initial state which is false.
The error more than likely comes from the ModalActions.ts or ModalReducer.ts.
Note: All the code provided below are just snippets. I omitted alot of stuff and left only what I thought could be the issue.
This is my ModalTypes.ts
export const SHOW_MODAL = "SHOW_MODAL";
interface ShowModal {
type: typeof SHOW_MODAL;
payload: boolean;
}
export type ModalActionTypes = ShowModal;
This is my ModalActions.ts
import { SHOW_MODAL, ModalActionTypes } from "./ModalTypes";
export function UpdateModal(modal: boolean): ModalActionTypes {
return {
type: SHOW_MODAL,
payload: modal
};
}
This is my IModalState.ts
export interface IModalState {
showModal: boolean;
}
This is my ModalReducer.ts. **I will probably make actions and types to hide the modal as well
import { ModalActionTypes, SHOW_MODAL } from "../actions/ModalTypes";
import { IModalState } from "../models/IModalState";
const initialState: IModalState = {
showModal: false
};
export function modalReducer(state = initialState, action: ModalActionTypes) {
switch (action.type) {
case SHOW_MODAL:
return {
...state,
showModal: action.payload
};
default:
return state;
}
}
This is my App.tsx
<ListGroup
onUpdateModal={this.props.onUpdateModal}
showModalState={this.props.showModalState}
/>
const mapStateToProps = (state: AppState) => ({
showModalState: state.modal
});
const mapDispatchToProps = (dispatch: any) => {
return {
onUpdateModal: bindActionCreators(UpdateModal, dispatch)
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
This is my ListGroup.tsx
import { UpdateModal } from "../actions/ModalActions";
import { IModalState } from "../models/IModalState";
interface IProps {
onUpdateModal: typeof UpdateModal;
showModalState: IModalState;
}
// interface IState {
// showModal: boolean;
// }
export class ListGroup extends React.Component<IProps> {
// IState
// public state: IState = {
// showModal: false
// };
// showModal = () => {
// // Show the modal
// this.setState({ showModal: true });
// };
public render() {
// const { showModal } = this.state;
return (
<div>
<ul
className="list-group"
style={{
marginTop: "20px",
display: "inline-block"
}}
>
{filterTests.map(filterTest => (
<li
className="list-group-item list-group-item-action d-flex justify-content-between align-items-center"
onClick={() => {
this.props.onUpdateModal(true);
console.log(this.props.onUpdateModal(true));
console.log(this.props.showModalState);
this.props.onUpdateSelectedTest(filterTest);
// this.showModal();
}}
>
{filterTest.companyPN}: {filterTest.description}
</li>
))}
</ul>
{/* Show the modal if showModal is true */}
{this.props.showModalState && (
<TestGroup
testState={this.props.testState}
onUpdateSelectedWedge={this.props.onUpdateSelectedWedge}
/>
)}
</div>
);
}
}
This my TestGroup.tsx
interface IProps {
onUpdateModal: typeof UpdateModal;
showModalState: IModalState;
}
export class TestGroup extends React.Component<IProps> {
// hideModal = () => {
// this.setState({
// showModal: !this.props.showModal
// });
// };
public render() {
return (
<div>
<div className="modal" style={{ display: "inline-block" }}>
<div className="modal-dialog" role="document">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title"></h5>
<button
type="button"
className="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
</div>
<div className="modal-body">
</div>
<div className="modal-footer">
<button
// onClick={() => {
// this.hideModal();
// }}
type="button"
className="btn btn-secondary"
data-dismiss="modal"
>
Close
</button>
</div>
</div>
))}
</div>
</div>
</div>
);
}
}
export default TestGroup;
I'd rather leave this as a comment, but I don't have the privilege at the moment.
In your app.ts mapStateToProps function, I think you want showModalState to be
showModalState: state.modal.showModal
In Apps.tsx instead of this.props.showModalState it should have been this.props.showModalState.showModal
{this.props.showModalState.showModal && (
<TestGroup
testState={this.props.testState}
onUpdateSelectedWedge={this.props.onUpdateSelectedWedge}
/>
)}