React useSelector not working, what am I doing wrong? - reactjs

I have a selectors folder with the selector.js file
const isRecipeFavorited = state => recipeId => {
const recipe = state.find(recipe => recipe.id === recipeId)
console.log(`Selector isRecipeFavourtied: ${recipeId}`)
return recipe ? recipe.is_fav : false
}
This is my favicon.js file which calls this useSelector.
import React, {useState, useEffect} from 'react'
import { FontAwesome } from '#expo/vector-icons'
import { View, TouchableOpacity,StyleSheet, Text, Alert } from 'react-native'
import {isRecipeFavorited} from '../selectors/selectors'
import {useSelector} from 'react-redux'
import { favids } from '../reducers/favids'
const FavIcon = ({recipeid, onToggle, isFavourite, text}) => {
const isFavNew = useSelector(isRecipeFavorited(recipeid))
return (
<View>
<TouchableOpacity style={styles.favItem} onPress={() => onToggle(recipeid)}>
<FontAwesome name={isFavNew === true ? 'heart' : 'heart-o'} size={40} color='red' />
<Text> {text}</Text>
</TouchableOpacity>
</View>
)
}
export default FavIcon
I keep getting an error saying my selector is not a function. _selectors.isRecipeFavourited is not a function.
I am trying to retrieve the value of the recipe.is_fav from the state.
I am also using Redux in this project.

I think you need to reverse state and recipeId in your selector function, i.e.:
const isRecipeFavorited = recipeId => state => {...}
This is a valid useSelector:
const thing = useSelector(state => state.thing);
In your case, you're calling a function with another type of argument, which in turn should return a function of the type that useSelector is expecting.

This is solved by drilling down into the favids object.
The selector function has been modified as below.
const recipe = state.favids.find(recipe => recipe.recipeid === recipeId)
return recipe ? recipe.is_fav : false
}```

Related

Cannot read values from array object from the map function in React

I am trying to pass value from an array items object to another component using map(). All values is coming from api call and is showed in console.But when passing the value from here to Titlecard, I am getting error cannot read properties of undefined map()?I have given the code.Also I have shared Titlecard. Always passing only one record into the array Can anyone guide me here? Thanks
import axios from "axios";
import React, { useEffect, useState } from "react";
import { Container } from "react-bootstrap";
import Titlecard from "./Titlecard";
import { HeroesUrl } from "../apiurl/HeroesApi";
const TitleHero = () => {
const [items, setItems] = useState([]);
useEffect(() => {
axios.get(HeroesUrl).then((response) => {
setItems(response.data);
console.log(response.data);
});
}, []);
return (
<>
<Container>
<div>
{items.map((item) => {
return (
<>
<Titlecard key={item.id} item={item} />
</>
);
})}
</div>
</Container>
</>
);
};
export default TitleHero;
import React, { useEffect, useState } from "react";
const Titlecard = (item) => {
return (
<>
<div> item.firstName </div>
</>
);
};
export default Titlecard;
I edit my answer after I saw you shared Titlecard component.
There are 2 problems.
The first is in your return, it should be:
<div>{item.firstName}</div>
Because what you return before is just a string like "item.firstName".
Second, you have to make a destructuring to the props in Titlecard like:
const Titlecard = ({item}) => {...}
or return:
<div>{item.item.firstName}</div>
The first one is your props name, the second is the prop you pass.
So, with using destructuring Titlecard should be like this:
import React from "react";
const Titlecard = ({item}) => {
return (
<>
<div>{item.firstName}</div>
</>
);
};
export default Titlecard;
Please share Titlecard component code.
It's look like that there is a part in the Titlecard component that use the item from the map. In the first time before the axios call finished, the prop item is still empty array, so if you use in the Titlecard component item.something you will get an undefined error.
One solution is to add a loader that initial to true, and after the axios call finished set it to false, so if the loader is true, render a loader, else render your map code.
Another solution is adding ? when you use item in Titlecard component, like: item?.something, what means only if item is not null or undefined.

Use hook in export function - React Native

I want to write 1 common function that I will use in different functional components.
This generic function uses hooks and I get the error: Error: Invalid hook call. Hooks can only be called inside the body of a functional component.
Example of my code:
App.js
import React from 'react';
import {
Text,
TouchableOpacity,
} from 'react-native';
import { Change } from 'static/Change';
export default function App() {
return (
<TouchableOpacity
onPress={() => {
Change();
}}
>
<Text>Click Me!</Text>
</TouchableOpacity>
);
}
Change.js
import React from 'react';
export const Change = () => {
const [State, setState] = React.useState(0);
// Other hook work.
// The function returns nothing
};
What is my mistake and how can I fix it?
Hooks has some rules to follow - https://reactjs.org/docs/hooks-rules.html
Refactor code as below
import React from "react";
import { Text, TouchableOpacity } from "react-native";
function useChange() {
const [state, setState] = React.useState(0);
function change(value) {
setState(value);
}
return { change, state };
}
export default function App() {
const { change, state } = useChange();
return (
<TouchableOpacity
onPress={() => {
// Update state value on press
change(state + 1);
}}
>
<Text>Click Me!{state}</Text>
</TouchableOpacity>
);
}

How to prevent state passed as props from giving undefined

Good day ,I'm quite new to reactjs and I'm trying to pass state as props but it keeps giving me undefined in the component I want to make use of it in. This is where I pass the state, workspacelist is the component receiving the state
import React,{useState} from 'react'
import Background8 from '../Images/house3.jpg';
import { useHistory } from 'react-router-dom';
import Workspacelist from '../Workspace/Workspacelist';
function BoardList({ boards }) {
const history = useHistory()
const [currentid, setcurrentid] = useState("")
const navigate = (id) => {
setcurrentid(id)
history.push('./workspace');
return <Workspacelist id = {currentid} />
}
return (
<>
{
boards.map((board) => (
<li key={board.id} className="boardlist" style={styles} onClick={() => navigate(board.id)}>
<h3>{board.title}</h3>
</li>
))}
</>
)
}
export default BoardList
This is the short version of workspacelist component where I receive it
import React from 'react'
function Workspacelist({ id }) {
console.log(id)
}
but any time I log id it returns undefined

React native typescript: usecontext functions not firing from inside child component

I have an issue when i try to use functions from a context inside a child component in a React native android app.
Below is my code for the context, and the form component im using it in (stripped down for brevity).
The "isFormOpen" object can be read no problem from inside any children that is wrapped in the provider, but when i try to call the "toggleForm" function from the same child component, it does nothing, no console errors either.
I have another context which is identical in structure and syntax except for vairable and function names etc, and that works perfectly, so im a bit confused as to why this does not work. I removed the other context, thinking there might be some type of conflict, but didnt solve it.
AccountContext.tsx
import React, { FC, createContext, useContext, useState } from 'react';
interface AccountContextType {
isFormOpen: boolean,
toggleForm: (toggle: boolean) => void
};
export const AccountContext = createContext<AccountContextType>({
isFormOpen: false,
toggleForm: () => null
});
export const AccountContextProvider: FC = props => {
const [formOpen, setFormOpen] = useState<boolean>(false);
const toggleForm = (toggle: boolean) => {
setFormOpen(toggle);
}
const value: AccountContextType = {
isFormOpen: formOpen,
toggleForm
}
return (
<AccountContext.Provider value={value}>
{props.children}
</AccountContext.Provider>
)
}
export const useAccountContext = () => useContext(AccountContext);
TrackUploadForm.js
import React from 'react';
import { SafeAreaView } from 'react-native';
import { Button } from 'react-native-paper';
import { useAccountContext } from '../contexts/AccountContext';
import { AccountContextProvider } from '../contexts/AccountContext';
const TrackUploadForm = () => {
const accountContext = useAccountContext();
return (
<AccountContextProvider>
<SafeAreaView>
<Button onPress={() => accountContext.toggleForm(false)} mode='outlined'>Cancel</Button>
</SafeAreaView>
</AccountContextProvider>
)
};
export default TrackUploadForm;
useAccountContext is called outside the provider
export default function App() {
return (
<AccountContextProvider>
<Content />
</AccountContextProvider>
);
}
const Content = () => {
const accountContext = useAccountContext();
return (
<div className="App">
<h1>{accountContext.isFormOpen ? "true" : "false"}</h1>
<Button onPress={() => accountContext.toggleForm(false)} mode='outlined'>Cancel</Button>
</div>
);
};
accountContext.toggleForm(false) <-- always false, change it to accountContext.toggleForm(!accountContext.isFormOpen)
Together we have
https://codesandbox.io/s/cranky-panini-yo129

React Native save change switch with Async Storage

Im new in React Native, I have a problem with Switch, I want to save changes, dark mode and Switch, when I turn off the app and come back my changes should be saved. When I close the app, my switch came back to first position and dark mode does not work. I know that Im doing something wrong, but I did not mobile app and this is my first time and I dont know how to use AsyncStorage in this App to work this. Can somebody help me solve this problem?
import React, { createContext, useState, useEffect } from 'react';
import { AsyncStorage } from 'react-native';
export const DarkModeContext = createContext();
export default function DarkModeContextProvider(props) {
const [switchMode, setSwitchMode] = useState(false);
useEffect(() => {
let switch1 = switchMode;
AsyncStorage.setItem('switch1', JSON.stringify(switch1));
});
const SwitchThis = () => {
setSwitchMode(!switchMode);
};
return (
<DarkModeContext.Provider
value={{
switchMode,
SwitchThis
}}
>
{props.children}
</DarkModeContext.Provider>
);
}
and next component:
import React, { useState, useContext } from 'react';
import { View, ScrollView, TouchableOpacity, Text, AsyncStorage } from 'react-native';
import { List } from 'react-native-paper';
import BackgroundImage from './BackgroundImage';
import Clock from './Clock';
import TabIcon from './TabIcon';
import AddButton from './AddButton';
import { DarkModeContext } from './app-context';
const HomeScreen = () => {
const { switchMode } = useContext(DarkModeContext);
displayData = async () => {
try {
let switch1 = await AsyncStorage.getItem('switch1', function (err, switch1) {
JSON.parse(switch1)
}
)
return switch1
}
catch (error) {
return error
}
}
return (
<View
style={{
flex: 1,
backgroundColor: !switchMode ? 'white' : '#353535'
}}
>
<BackgroundImage fabButton={<AddButton/>}>
<Clock />
</BackgroundImage>
<ScrollView>
<List.Section>
<List.Subheader style={{ color: !switchMode ? 'black' : 'white' }}>
Task List
</List.Subheader>
<TouchableOpacity onPress={displayData}>
<Text>Click displayData</Text>
</TouchableOpacity>
</List.Section>
</ScrollView>
</View>
);
};
You are importing AsyncStorage from 'react-native' which is deprecated
use #react-native-community/react-native-async-storage
npm i #react-native-community/react-native-async-storage
And on your home screen you are not calling the function displayData() so how is data supposed to be displayed without function call.
and i do suggest making separate functions for writing and reading from async storage, it will help you reduce your code and time.
Like this:
let storeData=(name, obj)=> {
return new Promise((resolve,reject)=>{
let jsonOfItem = JSON.stringify(obj)
AsyncStorage.setItem(name, jsonOfItem).then(r=>resolve(jsonOfItem))
.catch(e=>reject(e))
})
}
let readData=(name)=> {
return new Promise((resolve,reject)=>{
//we want to wait for the Promise returned by AsyncStorage.setItem()
//to be resolved to the actual value before returning the value
AsyncStorage.getItem(name).then(r=> resolve(JSON.parse(r)) )
.catch(e=>reject(e))
})
}
//Now you can just read write easily in async function like this:
let fetchedData = await readData("key")
//and for storing data.
storeData("key",object)

Resources