property map is showing undefined - javascript

Here I want to render purpose array. I am using map here but still its showing that map is undefined.
Unhandled Rejection (TypeError): Cannot read property 'map' of undefined
//userWorkDetails.js
const UserAccountDetails = props => {
const { className, userid, user, ...rest } = props;
console.log(`purpose::::${props.purpose}`)
const classes = useStyles();
const [parameters, setParameters] = useState([]);
// const [user, setUser] = useState({});
const [open, setopen] = useState(false);
Here I am using purpose.
const [purpose,setPurpose]=useState(" ");
Here I am mapping purpose to print the elements in the array.
async function createPurpose(){
let lookingFor="";
console.log(`purpose::::::create:${props.purpose}`);
props.purpose.map((element)=>{
lookingFor=lookingFor+element+", ";
});
lookingFor=lookingFor.substring(0,lookingFor.length-1);
setPurpose(lookingFor);
}
//userDetails.js
const UserDetail = (props) => {
const classes = useStyles();
const [isData,setIsdata] = useState(false);
const [user, setUser] = useState({});
const [purpose,setPurpose]=useState([]);
useEffect(()=>{
sendHttpCall('GET', `users/user_detail/${props.match.params.userid}`, null, props).then((response) => {
setPurpose(response.purpose);
Here I have made an array and I am sending response to userWorkDetails.
let s=["WFH","Hiring","Freelance"];
response.lookingFor=s;
setUser(response);
console.log( `outer:purpose:${purpose}`)
})
},[]);

Related

Empty data after using UseEffect ReactJs

I want to get news but i have an empty dictionary in the first render.
My useEffect
const [news, setNews] = useState({});
const [page, setPage] = useState(1);
const [user, setUser] = useState({});
useEffect(() =>{
const getNews = async() =>{
const newsData = await httpClient.get(`/feed/${pk}/?page=${page.toString()}`)
setNews(newsData.data);
const userData = await httpClient.get('/profile/')
setUser(userData)
}
getNews();
}, [page])
How can i get data in the first time render?
because you have [page] in the dependency array - add hook for initial render:
const [page, setPage] = useState(0);
useEffect(() => setPage(1), [])
You will always have your state what you initialize it as on first render, react won't wait until useEffect is finished before render since that would lock up the UI.
You need some sort of loading indicator while data is fetching, you can do this for example
const [loading, setLoading] = useState(true);
const [news, setNews] = useState({});
const [page, setPage] = useState(1);
const [user, setUser] = useState({});
useEffect(() =>{
const getNews = async() =>{
const newsData = await httpClient.get(`/feed/${pk}/?page=${page.toString()}`)
setNews(newsData.data);
const userData = await httpClient.get('/profile/')
setUser(userData)
setLoading(false)
}
setLoading(true)
getNews();
}, [page])
if (loading) {
return <>{"loading"}</>
}
change the return value to whatever you want, maybe you want to just return an empty <></> component so that when it first shows up it'll have all the data.

How to change a snippets of code from Class Component to Functional Component

Here is the code of the snippet I want to change to a Functional component, I write almost my code here now please check.
import _ from 'lodash';
import { ListItem, SearchBar, Avatar } from 'react-native-elements';
import { getUsers, contains } from './api/index';
function App(props) {
const [loading, setLoading] = useState(false);
const [data, setData] = useState([]);
const [error, setError] = useState(null);
const [fullData, setFullData] = useState([]);
const [query, setQuery] = useState();
useEffect(() => {
makeRemoteRequest();
},[query]);
const makeRemoteRequest = _.debounce(() => {
setLoading(true);
getUsers(20, query)
.then((users) => {
setLoading(false);
setData(users);
setFullData(users);
})
.catch((error) => {
setLoading(false);
});
}, 250);
const handleSearch = (text) => {
const formattedQuery = text.toLowerCase();
const data = _.filter(fullData, (user) => {
return contains(user, formattedQuery);
});
// I want to change the below code to work on Functioanl component
// this.setState({ data, query: text }, () => //this.makeRemoteRequest());
// New code here.....
};
I implemented it in a different way but not work.
You can have something like the following.
const [query, setQuery] = useState();
const [data, setData] = useState();
useEffect(() => {
makeRemoteRequest();
}, [query])
Read more about useEffect here
You're trying to make a set of data and text, then call a callback after the set.
There are several ways to obtain this behaviour.
What I would suggest you is to have a state (useState) which include data and text and then listen for the changes of this stage through a useEffect.
export default function App() {
const [request, setRequest] = useState({data: {}, text: ''});
const makeRemoteRequest = useCallback(() => console.log({request}),[request]);
useEffect(() => {
//on mount
setRequest({data: {obj:'with data'}, text: 'text'})
},[])
useEffect(() => {
makeRemoteRequest()
},[request,makeRemoteRequest])
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
What you can see here, it's a functional component which is:
setting a state on mount (read comment)
define a function makeRemoteRequest every time the state request changes through the useCallback hook
call the function makeRemoteRequest every time the state request or the callback makeRemoteRequest changes through the useEffect hook
EDIT:
import _ from 'lodash';
import { ListItem, SearchBar, Avatar } from 'react-native-elements';
import { getUsers, contains } from './api/index';
function App(props) {
const [loading, setLoading] = useState(false);
const [data, setData] = useState([]);
const [error, setError] = useState(null);
const [fullData, setFullData] = useState([]);
const [query, setQuery] = useState();
useEffect(() => {
makeRemoteRequest();
},[query]);
const makeRemoteRequest = _.debounce(() => {
setLoading(true);
getUsers(20, query)
.then((users) => {
setLoading(false);
setData(users);
setFullData(users);
})
.catch((error) => {
setLoading(false);
});
}, 250);
const handleSearch = (text) => {
const formattedQuery = text.toLowerCase();
const data = _.filter(fullData, (user) => {
return contains(user, formattedQuery);
});
setData(data);
setQuery(text);
}
};
Actually what you want is to trigger the function makeRemoteRequest, right now that you have to do in order to get it is to make the proper set (which means setQuery), which is going to trigger the useEffect

Invalid hook call with nested component call

I have the following code in my App.jsx:
render() {
return (
<BrowserView>
<CreateSession /> // works just fine
<QrCode address={CreateSession(this)} /> // throws 'Error: Invalid hook call.'
</BrowserView>)
}
CreateSession returns a string, which is fed into QrCode, to generate a Qr Code. My CreateSession looks like this:
const CreateSession = (props) => {
const userVideo = useRef();
const partnerVideo = useRef();
const peerRef = useRef();
const socketRef = useRef();
const otherUser = useRef();
const userStream = useRef();
useEffect(() => {
socketRef.current = io.connect("/");
socketRef.current.emit("join session", props.match.params.roomID);
// lots of code omitted, source is: https://github.com/coding-with-chaim/native-webrtc/blob/master/client/src/routes/Room.js
return uuid();
};
export default CreateSession;
What is the correct way to call CreateSession so that it returns the uuid right into QrCode? I am aware that I could have a state property in the App.jsx that gets set to uuid, that is then passed into QrCode, but is it possible to do it this way?
You can turn your CreateSession component into a wrapper.
const CreateSession = (props) => {
const userVideo = useRef();
const partnerVideo = useRef();
const peerRef = useRef();
const socketRef = useRef();
const otherUser = useRef();
const userStream = useRef();
const [uuid, setUuid] = useState(null);
useEffect(() => {
socketRef.current = io.connect("/");
socketRef.current.emit("join session", props.match.params.roomID);
// lots of code omitted, source is: https://github.com/coding-with-chaim/native-webrtc/blob/master/client/src/routes/Room.js
setUuid(uuid());
});
if (uuid === null) {
return null;
}
return (<>{props.children(uuid)}</>)
};
export default CreateSession;
Here is the usage.
render() {
return (
<BrowserView>
<CreateSession>
{(uuid) => (<QrCode address={uuid} />)}
</CreateSession>
</BrowserView>
)
}

Flickering on product loading

I learn React and explore various examples and tutorials. I tried to create an eshop according to the tutorial. But one thing is not clear to me. Flickers annoyingly while loading product or category. How could you get rid of it? What causes it?
Its this part of code:
export default function ProductScreen(props) {
const dispatch = useDispatch();
const productId = props.match.params.id;
const [qty, setQty] = useState(1);
const productDetails = useSelector((state) => state.productDetails);
const { loading, error, product } = productDetails;
const userSignin = useSelector((state) => state.userSignin);
const { userInfo } = userSignin;
const productReviewCreate = useSelector((state) => state.productReviewCreate);
const {
loading: loadingReviewCreate,
error: errorReviewCreate,
success: successReviewCreate,
} = productReviewCreate;
const [rating, setRating] = useState(0);
const [comment, setComment] = useState('');
Here is example: https://amazona.webacademy.pro/
Here is full code: https://github.com/basir/amazona/blob/master/frontend/src/screens/ProductScreen.js
Thanks

React Hook : Correct way of using custom hook to handle onClick Event?

As the title said, what is the correct way of using custom hook to handle onClick Event?
This codesandbox application will display a new quote on the screen when user clicks the search button.
function App() {
const [{ data, isLoading, isError }, doFetch] = useDataApi(
"https://api.quotable.io/random"
);
return (
<Fragment>
<button disabled={isLoading} onClick={doFetch}>
Search
</button>
{isError && <div>Something went wrong ...</div>}
{isLoading ? <div>Loading ...</div> : <div>{data.content}</div>}
</Fragment>
);
}
I created a custom hook called useDataApi() which would fetch a new quote from an API. In order to update the quote when the user clicks the button, inside the useDataApi(), I created a handleClick() which will change the value of a click value to trigger re-render. And this handleClick() function will be return back to App()
const useDataApi = initialUrl => {
const [data, setData] = useState("");
const [click, setClick] = useState(true);
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
const handleClick = () => {
setClick(!click);
};
useEffect(() => {
const fetchData = async () => {
setIsError(false);
setIsLoading(true);
try {
const result = await axios(initialUrl);
setData(result.data);
} catch (error) {
setIsError(true);
}
setIsLoading(false);
};
fetchData();
}, [initialUrl, click]);
return [{ data, isLoading, isError }, handleClick];
};
This is working, however, I don't feel this is the correct solution.
I also tried moving the fetchData() out of useEffect and return the fetchData(), and it works too. But according to the React Doc, it says it is recommended to move functions inside the useEffect.
const useDataApi = initialUrl => {
const [data, setData] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
const fetchData = async () => {
setIsError(false);
setIsLoading(true);
try {
const result = await axios(initialUrl);
setData(result.data);
} catch (error) {
setIsError(true);
}
setIsLoading(false);
};
useEffect(() => {
fetchData();
}, []);
return [{ data, isLoading, isError }, fetchData];
};
In addition, for creating these kinds of application, is the way that I am using is fine or there is another correct solution such as not using any useEffects or not create any custom Hook?
Thanks
Not sure if this is correct, but here is my solution.
const useDataApi = initialUrl => {
const [data, setData] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
const doFetch = async () => {
setIsError(false);
setIsLoading(true);
try {
const result = await axios(initialUrl);
setData(result.data);
} catch (error) {
setIsError(true);
}
setIsLoading(false);
};
return [{ data, isLoading, isError }, doFetch];
};
Btw, don't mutate state directly.
const handleClick = () => {
setClick(!click); // don't do this
setClick(prev => !prev); // use this
};
Your implementation is fine. We are also using something similar. Hope you find it useful.
function useApi(promiseFunction, deps, shouldRun=true){
// promisFunction returns promise
const [loading, setLoading] = useState(false)
const [data, setData] = useState(false)
const [error, setError] = useState(false)
const dependencies: any[] = useMemo(()=>{
return [...dependencyArray, shouldRun]
},[...dependencyArray, shouldRun])
const reload = () => {
async function call() {
try {
setError(null)
setLoading(true)
const res = await promiseFunction();
}
catch (error) {
setError(error)
}
finally {
setLoading(false)
}
}
call();
}
useEffect(() => {
if(!shouldRun) return
setResult(null) //no stale data
reload()
}, dependencies)
return {loading, error, data, reload, setState: setData}
}
Below code will provide some idea about how to use it.
function getUsersList(){
return fetch('/users')
}
function getUserDetail(id){
return fetch(`/user/${id}`)
}
const {loading, error, data } = useApi(getUsersList, [], true)
const {loading: userLoading, error: userError, data: userData}
= useApi(()=>getUserDetail(id), [id], true)

Categories