Redux - useSelector returns state as undefined - reactjs

I'm following a tutorial on learning Redux and I'm stuck at this point where state that should have an image url is returned as undefined.
Image is successfully saved in firbase storage and dispatched but when I try to get the url on new route with useSelector it is undefined.
import React, {useEffect} from "react";
import {useSelector} from "react-redux";
import {useHistory} from "react-router-dom";
import "./ChatView.css";
import {selectSelectedImage} from "./features/appSlice";
function ChatView() {
const selectedImage = useSelector(selectSelectedImage);
const history = useHistory();
useEffect(() => {
if(!selectedImage) {
exit();
}
}, [selectedImage])
const exit = () => {
history.replace('/chats');
}
console.log(selectedImage)
return (
<div className="chatView">
<img src={selectedImage} onClick={exit} alt="" />
</div>
)
}
export default ChatView
reducer created for chat (slice):
import { createSlice } from '#reduxjs/toolkit';
export const appSlice = createSlice({
name: 'app',
initialState: {
user:null,
selectedImage:null,
},
reducers: {
login: (state, action) => {
state.user = action.payload;
},
logout: (state) => {
state.user = null;
},
selectImage:(state, action) => {
state.selectedImage = action.payload
},
resetImage:(state) => {
state.selectedImage = null
}
},
});
export const { login, logout, selectImage, resetImage} = appSlice.actions;
export const selectUser = (state) => state.app.user;
export const selectSelectedImage = (state) => state.app.selectImage;
export default appSlice.reducer;
and code for dispatching that imageURL which when i console.log it gives the correct url:
import {Avatar} from "#material-ui/core";
import StopRoundedIcon from "#material-ui/icons/StopRounded"
import "./Chat.css";
import ReactTimeago from "react-timeago";
import {selectImage} from "./features/appSlice";
import {useDispatch} from "react-redux";
import {db} from "./firebase";
import {useHistory} from "react-router-dom";
function Chat({id, username, timestamp, read, imageUrl, profilePic}) {
const dispatch = useDispatch();
const history = useHistory();
const open = () => {
if(!read) {
dispatch(selectImage(imageUrl));
db.collection('posts').doc(id).set({read:true,}, {merge:true});
history.push('/chats/view');
}
};
return (
<div onClick={open} className="chat">
<Avatar className="chat__avatar" src={profilePic} />
<div className="chat__info">
<h4>{username}</h4>
<p>Tap to view - <ReactTimeago date={new Date(timestamp?.toDate()).toUTCString()} /></p>
</div>
{!read && <StopRoundedIcon className="chat__readIcon" />}
</div>
)
}
export default Chat

Your selector is trying to access the wrong field.
export const selectSelectedImage = (state) => state.app.selectImage;
Should actually be:
export const selectSelectedImage = (state) => state.app.selectedImage;
as your state has selectedImage field and not selectImage.

Related

Error: cannot read properties of undefined in react-redux

I am trying to loop through every movie inside the movies array and render it.
There are 4 sections Trending,NewDisney,Originals,Recommended.
The movies' data is stored inside the firestore and I am retrieving it from there.
Here's the code
(All the styling is removed to make the code short here)
movieSlice.js file
import { createSlice } from "#reduxjs/toolkit";
const initialState = {
recommend: null,
newDisney: null,
original: null,
trending: null,
};
const movieSlice = createSlice({
name: "movie",
initialState,
reducers: {
setMovies: (state, action) => {
state.recommend = action.payload.recommend;
state.newDisney = action.payload.newDisney;
state.original = action.payload.original;
state.trending = action.payload.trending;
},
},
});
export const { setMovies } = movieSlice.actions;
export const selectRecommend = (state) => state.movie.recommend;
export const selectNewdisney = (state) => state.movie.newDisney;
export const selectOriginal = (state) => state.movie.original;
export const selectTrending = (state) => state.movie.trending;
export default movieSlice.reducer;
Recommends.js file
import React from "react";
import styled from "styled-components";
import { Link } from "react-router-dom";
import p1 from "../images/sample_img.jpg";
import { selectRecommend } from "../features/movies/movieSlice";
import { useSelector } from "react-redux";
const Recommend = () => {
const movies = useSelector(selectRecommend);
return (
<Container>
Recommended movies for you!
<Content>
{movies &&
movies.map((movie, key) => {
<Link to={"/detail/" + movie.id} key={key}>
<Wrap imgUrl={movie.cardImg} alt={movie.title} />
</Link>;
})}
</Content>
</Container>
);
};
export default Recommend;
Home.js file (Where all the components are imported)
import React, { useEffect } from "react";
import styled from "styled-components";
import ImgSlider from "./ImgSlider";
import NewDisney from "./NewDisney";
import Originals from "./Originals";
import Recommend from "./Recommends";
import Trending from "./Trending";
import Viewers from "./Viewers";
import { setMovies } from "../features/movies/movieSlice";
import { useDispatch, useSelector } from "react-redux";
import db from "../firebase";
import { selectUserName } from "../features/user/userSlice";
import { collection, query, onSnapshot } from "firebase/firestore";
const Home = () => {
const dispatch = useDispatch();
const userName = useSelector(selectUserName);
useEffect(() => {
let recommends = [];
let newDisneys = [];
let trendings = [];
let originals = [];
console.log("Hello!");
const q = query(collection(db, "movies"));
onSnapshot(q, (snapshot) => {
snapshot.docs.map((doc) => {
console.log(doc);
switch (doc.data().type) {
case "recommend":
recommends = [...recommends, { id: doc.id, ...doc.data() }];
break;
case "new":
newDisneys = [...newDisneys, { id: doc.id, ...doc.data() }];
break;
case "trending":
trendings = [...trendings, { id: doc.id, ...doc.data() }];
break;
case "originals":
originals = [...originals, { id: doc.id, ...doc.data() }];
break;
}
});
dispatch(
setMovies({
recommend: recommends,
trending: trendings,
newDisney: newDisneys,
original: originals,
})
);
});
}, [userName]);
return (
<Container>
<ImgSlider />
<Viewers />
<Recommend />
<NewDisney />
<Originals />
<Trending />
</Container>
);
};
export default Home;
But unfortunately this is not working and I am getting this error for all components (Recommend,Trending,NewDisney,Originals)
movieSlice.js:26 Uncaught TypeError: Cannot read properties of undefined (reading 'recommend')
at selectRecommend (movieSlice.js:26:1)
at memoizedSelector (with-selector.development.js:79:1)
at getSnapshotWithSelector (with-selector.development.js:134:1)
at mountSyncExternalStore (react-dom.development.js:16799:1)
at Object.useSyncExternalStore (react-dom.development.js:17727:1)
at useSyncExternalStore (react.development.js:1676:1)
at useSyncExternalStoreWithSelector (with-selector.development.js:145:1)
at useSelector (useSelector.js:41:1)
at Recommend (Recommends.js:8:1)
at renderWithHooks (react-dom.development.js:16305:1)
Please help me.
The error is occurring where you are doing this
export const selectRecommend = (state) => state.movie.recommend;
export const selectNewdisney = (state) => state.movie.newDisney;
export const selectOriginal = (state) => state.movie.original;
export const selectTrending = (state) => state.movie.trending;
Remove these and use this way to get values in App.js
const { recommend, newDisney, original, trending } = useSelector((state) => state.movie);

React-Redux Search/Filter component countries API

I have problem with initialization of search and filter for ma countries api. I have stuck with problem how to implement code. I will be gratefull for any help or some advices how to do this. My files look like this:
Store.js
import { applyMiddleware, combineReducers, createStore, compose } from 'redux'
import getCountries from './getCountries'
const initialState = {
variable: {
data: [],
},
filters: {
searchPhrase: '',
continent: ''
}
}
const reducers = {
variable: getCountries, // variablesReducer
}
const storeReducer = combineReducers(reducers)
const store = createStore(
storeReducer,
initialState,
compose(applyMiddleware(), window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()) // przed deployem usunac
)
export default store
SearchPhraseRedux.js
//SearchEngine
export const getData = ({variable}, filters) => {
if(!filters.searchPhrase){
return variable.data
}
//Logic
//export const getCountryByName = ({variable}, name) =>
//variable.data.find(e=>e.name.common === name)
}
const reducerName = 'variable'
const createActionName = (name) => `app/${reducerName}/${name}`
export const SET_DATA = createActionName("SET_DATA")
export const setData = payload => ({payload, type: SET_DATA})
export default function reducer(statePart=[], action={}){
switch(action.type) {
case SET_DATA:
return {...statePart, data: action.payload}
default:
return statePart
}
}
countryContainer.js
import { connect } from "react-redux"
import { getData, setData} from '../../redux/getCountries'
import Countries from "./countries"
const mapStateToProps = (state) => ({
data: getData(state),
})
const mapDispatchToProps = dispatch =>({
setData: (value) => dispatch(setData(value)),
})
export default connect(mapStateToProps, mapDispatchToProps)(Countries)
countries.js
import React from 'react'
import { useEffect} from 'react'
import Axios from 'axios'
import '../../../src/index.css'
import {Link} from 'react-router-dom'
const Countries = ({data,setData}) => {
const url = 'https://restcountries.com/v3.1/all'
useEffect(() => {
Axios.get(url)
.then((rest) =>{
setData(rest.data)
})
},[url, setData])
return (
<div>
<section className='grid'>
{data.map((country) => {
const {population, region, capital} = country
const {png} = country.flags
const {official, common} = country.name
return <article key={common}>
<div>
<Link classsName='link' to={`/countries/${common}`}>
<img src ={png} alt={official}/>
</Link>
<div className='details'>
<h3>{common}</h3>
<h4>Population: <span>{population}</span></h4>
<h4>Region: <span>{region}</span></h4>
<h4>Capital: <span>{capital}</span></h4>
</div>
</div>
</article>
})}
</section>
</div>
)
}
export default Countries
I have tried to get One country like this:
export const getCountryByName = ({variable}, name) => variable.data.find(e=>e.name.common === name)
but,by extending this code, it is difficult for me to make search and filter

I have started working with React Native-Js for web app development and am stuck at a point wiith Dispatch function

I am trying to change state of my home page and in that basically changing the movies.
However when I run my dispatch it shows the error as shown in the pic attached.
Aso it is clearly not working properly because the movies array is showing 0 elements.
Home.js
import React, { useEffect } from 'react';
import styled from 'styled-components';
import ImgSlider from './ImgSlider';
import Viewers from './Viewers';
import Movies from './Movies';
import db from '../firebase';
import { useDispatch } from "react-redux";
import { setMovies } from "../features/movie/movieSlice";
function Home() {
const dispatch = useDispatch();
useEffect(() => {
db.collection("movies").onSnapshot((snapshot) => {
let tempMovies = snapshot.docs.map((doc) => {
console.log(doc.data());
return { id:doc.id, ...doc.data() }
})
dispatch(setMovies(tempMovies));
});
}, [])
Movies.js
import React from 'react'
import styled from 'styled-components';
import { selectMovies } from "../features/movie/movieSlice";
import { useSelector } from "react-redux";
function Movies() {
const movies = useSelector(selectMovies);
console.log("This is movies", movies);
return (
<Container>
<h4>Recommender For You</h4>
<Content>
{movies &&
movies.map((movie) => (
<Wrap>
<img src={movie.cardImg} />
</Wrap>
))
}
</content>
</container>);
movieSlice.js
import {createSlice} from '#reduxjs/toolkit';
const initialState={
movies:[ ]
}
const movieSlice = createSlice({
name:"movie",
initialState,
reducer:{
SetMovies: (state, action) =>{
state.movies= action.payload;
}
}
})
export const {setMovies} = movieSlice.actions;
export const selectMovies = (state)=>state.movie.movies;
export default movieSlice.reducer;

Cannot read property 'user' of undefined, React Redux

I have been getting this error "Cannot read property 'user' of undefined" in a userSlice.js which by default is named as counterSlice.js in react-redux. I have tried exporting by changing names and function names too, and I guess I am exporting the right function.
any suggestions or fix that might get it running?
Here is my userSlice.js file,
import { createSlice } from '#reduxjs/toolkit';
export const userSlice = createSlice({
name: 'user',
initialState: {
user: null,
},
reducers: {
login: (state, action) => {
state.user = action.payload;
},
logout: (state) => {
state.user = null;
},
},
});
export const { login, logout} = userSlice.actions;
export const selectUser = state => state.user.user;
export default userSlice.reducer;
here is the store.js file,
import { configureStore } from '#reduxjs/toolkit';
import userReducer from '../features/userSlice';
export default configureStore({
reducer: {
counter: userReducer,
},
});
and here is the App.js file where I am trying to make the login user state to be logged in,
import React, {useEffect} from 'react';
import './App.css';
import Homescreen from "./screens/Homescreen";
import LoginScreen from "./screens/LoginScreen";
import {auth} from "./firebase";
import {useDispatch, useSelector} from "react-redux";
import {login, logout, selectUser} from "./features/userSlice";
import {BrowserRouter as Router, Switch,Route} from 'react-router-dom';
function App() {
const user = useSelector(selectUser);
const dispatch = useDispatch();
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((userAuth) => {
if(userAuth){
dispatch(login({
uid: userAuth.uid,
email: userAuth.email,
})
);
} else{
dispatch(logout())
}
});
return unsubscribe;
}, []);
return (
<div className="App">
<Router>
{!user ? (
<LoginScreen/>
):(
<Switch>
<Route exact path="/">
<Homescreen />
</Route>
</Switch>
)}
</Router>
</div>
);
}
export default App;
The problem is here
export const selectUser = state => state.user.user;
You created slice with name counter here
export default configureStore({
reducer: {
counter: userReducer,
},
});
Try
export const selectUser = state => state.counter.user;
Or rename counter to user

react/redux app - TypeError: Cannot read property 'user' of undefined

I am creating a react app, when getting data from redux. I am facing the below error message in browser. please check and let me know what am I missing.
I am using create-react-app redux-toolkit setup template to create the app
Here is my app.js:
import React from "react";
import { useSelector } from "react-redux";
import "./App.css";
import { selectUser } from "./features/userSlice";
import Header from "./components/Header";
import Sidebar from "./components/Sidebar";
import Feed from "./components/Feed";
import Login from "./components/Login";
function App() {
const user = useSelector(selectUser);
return (
<div className="App">
<Header />
{ !user ? (
<Login />
) : (
<div className="main_content">
<Sidebar />
<Feed />
</div>
)}
</div>
);
}
export default App;
below you can find the redux reducer and actions
import { createSlice } from '#reduxjs/toolkit';
export const userSlice = createSlice({
name: 'user',
initialState: {
user: null,
},
reducers: {
login: (state, action) => {
state.value = action.payload
},
logout: (state, action) => {
state.user = null
}
},
});
export const { login, logout } = userSlice.actions;
export const selectUser = (state) => state.user.user;
export default userSlice.reducer;
below is the screenshot of error which. I'am getting when running the app
Working example for you, be sure you configured your store correctly. You should separate this into responding files.
import React from "react";
import { combineReducers, createStore, createSlice } from "#reduxjs/toolkit";
import { connect, Provider, useDispatch, useSelector } from "react-redux";
// your part
const userSlice = createSlice({
name: "user",
initialState: {
user: null
},
reducers: {
login: (state, action) => {
state.user = action.payload;
},
logout: (state, action) => {
state.user = null;
}
}
});
const { login, logout } = userSlice.actions
const selectUser = (state) => state.user.user;
// what I added
const reducer = combineReducers({
user: userSlice.reducer
});
const store = createStore(reducer);
const Main = (props) => {
const dispatch = useDispatch() // I used this to check if reducers work
const user = useSelector( selectUser )
return (
<div onClick={ () => { dispatch(login({name: "Adam"})) }}>
{ !user ? "LOGIN" : "DASHBOARD "}
</div>
)
}
const mapStateToProps = (state) => ({
user: state.user
});
const Container = connect(mapStateToProps, { login, logout })(Main);
function App() {
return (
<Provider store={store}>
<Container/>
</Provider>
);
}
export default App;

Resources