React axios get return empty array - reactjs

As I mentioned, console.log print only empty array. I think the problem will related with async problem.
This is the error what I got.
So, I make delay in axios, return with isLoading but still not working.
Has any solution? Thanks for help!
Test.js(parent component, every state in here) -> MainTest.js -> Question.js
Test.js
import React, { useState, useEffect } from "react";
import Tutorial from "../Tutorial";
import MainTest from "../MainTest";
import axios from "axios";
const Test = () => {
const [count, setCount] = useState(0);
const [questionNum, setQuestionNum] = useState(0);
const [questionList, setQuestionList] = useState([]);
useEffect(() => {
axios.get("http://localhost:3001/get/question").then((response) => {
setQuestionList(response.data);
})
}, []);
const questionHandler = () => {
setQuestionNum(questionNum + 1);
setCount(count + 1);
};
return (
<div>
<MainTest
questionList={questionList}
questionNum={questionNum}
questionHandler={questionHandler}
/>
</div>
);
};
export default Test;
MainTest.js
import React from 'react'
import styled from 'styled-components'
import ProgBar from './ProgBar'
import Question from './Question'
import SelectSec from './SelectSec'
function MainTest({questionList, questionNum, questionHandler}) {
return (
<TestWrap>
<ProgBar />
<Question questionList={questionList[questionNum]}/>
<SelectSec questionList={questionList[questionNum]} questionHandler={questionHandler}/>
</TestWrap>
)
}
export default MainTest
const TestWrap = styled.div`
width: 100vh;
height: 100vh;
background-image: url("./images/background/background.png");
`;
Question.js
import React from "react";
import Styled from "styled-components";
function Question({questionList}) {
console.log(questionList)
return (
<QuestionWrap>
<i className="far fa-calendar-alt"></i>
<h3>
{questionList.question.split('</br>').map(line => {
return(<>{line}<br/></>)
})}
</h3>
</QuestionWrap>
);
}
export default Question;
const QuestionWrap = Styled.div `
width: 100%;
height: 55%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
i{
color: #b56467;
font-size: 2rem;
margin-bottom: 2rem;
}
h3 {
text-align: center;
font-family: "UhBeeBEOJJI";
color: #3a1a00;
font-size: 2.7rem;
line-height: 3.4rem;
}
`;

in your Question component you need to had a condition in the return like:
function Question({questionList}) {
console.log(questionList)
return (
<QuestionWrap>
<i className="far fa-calendar-alt"></i>
<h3>
{questionList & questionList.question && questionList.question.split('</br>').map(line => {
return(<>{line}<br/></>)
})}
</h3>
</QuestionWrap>
);
}
export default Question;

Related

React - Typescript - How to function as prop to another component

There are three components Toggle, ToggleMenu, Wrapper
The toggle should be universal, and used for different functions
The Wrapper should only change background color when toggle is on
The question is how to pass the function that responcible for changing color to togglemenu, that it executs when switch toggle
App
import React from 'react';
import { Wrapper } from './containers/wrapper';
import { Button } from './components/buttons/button';
import { ToggleMenu } from './components/settings/settings';
const App = () => {
return (
<>
<Wrapper>
<Button />
<ToggleMenu />
</Wrapper>
</>
)
}
export default App;
ToggleMenu
import styled from "styled-components";
import { Toggle } from "../buttons/toggle";
import { WrapperProps } from "../../containers/wrapper";
import { test } from "./test"
const SettingsContainer = styled.div`
margin: auto;
width: 50%;
height: 50%;
display: flex;
align-items: center;
justify-content: center;
background-color: white;
`;
const Container = styled.div`
height: 50%;
width: 50%;
display: flex;
justify-content: center;
flex-direction: column;
background-color: lime;
`;
const TogCon = styled.div`
margin: 0.5em;
`;
export const ToggleMenu = (props: WrapperProps) => {
return (
<SettingsContainer>
<Container>
<TogCon>
<Toggle toggleText={"Dark mode"} onChange={props.handleTheme}/>
</TogCon>
<TogCon>
<Toggle toggleText={"Sth"} onChange={() => {console.log("Sth")}}/>
</TogCon>
</Container>
</SettingsContainer>
);
};
Wrapper
import React, { useState } from "react";
import styled from "styled-components";
export type WrapperProps = {
children?: React.ReactNode;
color?: string;
handleTheme?: () => void;
};
const Container = styled.div<WrapperProps>`
width: 100%;
height: 100%;
top: 0;
left: 0;
position: fixed;
background-color: ${props => props.color }
`
export const Wrapper = ({ children }: WrapperProps) => {
const [theme, setTheme] = useState("black")
const handleTheme = () => {
theme === "black" ? setTheme("white"): setTheme("black")
}
return(
<Container
color={theme}
handleTheme={handleTheme}
> { children }
</Container>
);
}
Was solved with React.cloneElement
export const Wrapper = (props: WrapperProps) => {
const [theme, setTheme] = useState("black")
const handleTheme = () => {
theme === "black" ? setTheme("white"): setTheme("black")
}
const childrenWithProps = React.Children.map(props.children, child => {
if (React.isValidElement(child)) {
return React.cloneElement(child, { handleTheme });
}
return child;
});
return(
<Container color={theme} >
{ childrenWithProps }
</Container>
);
}

Values getting undefined when consuming data using useContext in the child component

It is my first time working with useContext hook and I was trying to consume values with useContext in Navbar.js which I've provided in the parent component, but i'm receiving undefined only. In the Navbar.js when I console log user it showsundefined.
I tried to pass the data as props and it works fine. It only happens when I try with Context API. I think I messed up my context api implementation.
Created a context at AuthContext.js
import {createContext} from 'react'
export const AuthContext = createContext({})
Set values in App.js and wrapped using Provider.
import Login from "./pages/Login";
import Register from "./pages/Register";
import Cart from "./components/Cart/Cart";
import Slider from "./components/Slider";
import Categories from "./components/Categories";
import PopularProducts from "./components/PopularProducts";
import Navbar from "./components/Navbar";
import Checkout from "./components/Cart/Checkout";
import Products from "./components/Products";
import Footer from "./components/Footer";
import {
signInWithEmailAndPassword,
signOut,
onAuthStateChanged,
createUserWithEmailAndPassword,
} from "firebase/auth";
import { auth } from "./lib/firebase-config";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { useState, useEffect } from "react";
import { commerce } from "./lib/commerce";
import { AuthContext } from "./context/AuthContext";
const App = () => {
const [products, setProducts] = useState([]);
const [cart, setCart] = useState({});
const [order, setOrder] = useState({});
const [errorMessage, setErrorMessage] = useState("");
const [loginEmail, setLoginEmail] = useState("");
const [loginPassword, setLoginPassword] = useState("");
const [user, setUser] = useState({});
const [registerEmail, setRegisterEmail] = useState("");
const [registerPassword, setRegisterPassword] = useState("");
const [isLoggedIn, setIsLoggedIn] = useState(
localStorage.getItem("isLoggedIn")
);
onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser);
});
const loginHandler = async (event) => {
event.preventDefault();
try {
const user = await signInWithEmailAndPassword(
auth,
loginEmail,
loginPassword
);
setIsLoggedIn(true);
localStorage.setItem("isLoggedIn", true);
console.log(auth.currentUser.email);
} catch (error) {
console.log(error.message);
}
};
const registerHandler = async () => {
try {
const user = await createUserWithEmailAndPassword(
auth,
registerEmail,
registerPassword
);
setIsLoggedIn(true);
localStorage.setItem("isLoggedIn", true);
console.log({ registerEmail });
console.log(user);
} catch (error) {
console.log(error.message);
}
};
const logoutHandler = async () => {
await signOut(auth);
setIsLoggedIn(false);
localStorage.clear();
};
const fetchProducts = async () => {
const { data } = await commerce.products.list();
setProducts(data);
};
const fetchCart = async () => {
setCart(await commerce.cart.retrieve());
};
const handleAddToCart = async (productId, quantity) => {
const item = await commerce.cart.add(productId, quantity);
setCart(item.cart);
};
const handleUpdateCartQty = async (lineItemId, quantity) => {
const response = await commerce.cart.update(lineItemId, { quantity });
setCart(response.cart);
};
const handleRemoveFromCart = async (lineItemId) => {
const response = await commerce.cart.remove(lineItemId);
setCart(response.cart);
};
const handleEmptyCart = async () => {
const response = await commerce.cart.empty();
setCart(response.cart);
};
const refreshCart = async () => {
const newCart = await commerce.cart.refresh();
setCart(newCart);
};
const handleCaptureCheckout = async (checkoutTokenId, newOrder) => {
try {
const incomingOrder = await commerce.checkout.capture(
checkoutTokenId,
newOrder
);
setOrder(incomingOrder);
refreshCart();
} catch (error) {
setErrorMessage(error.data.error.message);
console.log(error.data);
}
};
useEffect(() => {
fetchProducts();
fetchCart();
}, []);
return (
<>
<AuthContext.Provider
value={
(user,
logoutHandler,
isLoggedIn) }>
<Navbar/>
</AuthContext.Provider>
</>
);
};
export default App;
Trying to consume data using useContext in Navbar.js
import { Badge } from "#material-ui/core";
import {
Search,
ShoppingCartOutlined,
TranslateOutlined,
} from "#material-ui/icons";
import { useContext } from "react";
import styled from "styled-components";
import { mobile } from "../responsive";
import { Link } from "react-router-dom";
import { AuthContext } from "../context/AuthContext";
const Parent = styled.div``;
const Container = styled.div`
height: 70px;
background-color: #b6e7f0;
${mobile({ height: "70px" })}
width: 98.75vw;
position: fixed;
top: 0;
z-index: 4;
`;
const Logo = styled.h4`
font-size: 30px;
color: black;
margin-left: 20px;
${mobile({ fontSize: "30px" })}
`;
const Wrapper = styled.div`
padding: 10px 0px;
display: flex;
justify-content: space-between;
max-width: 98.75vw;
${mobile({ padding: "10px 0px" })}
`;
const Left = styled.div`
display: flex;
align-items: center;
text-decoration: none;
width: 20%;
`;
const Center = styled.div``;
const Right = styled.div`
display: flex;
align-items: center;
margin-right: 20px;
justify-content: flex-end;
text-decoration: none;
${mobile({ flex: 2, justifyContent: "flexEnd" })}
`;
const Language = styled.span`
font-size: 14px;
cursor: pointer;
${mobile({ display: "none" })}
`;
const SearchContainer = styled.div`
flex: 1;
display: flex;
align-items: center;
margin-left: 0px;
margin-top: 10px;
padding: 5 px;
border-radius: 5px;
cursor: pointer;
${mobile({ display: "none" })}
&:focus {
}
`;
const Input = styled.input`
border: none;
&:focus {
outline: none;
}
width: 90%;
height: 100%;
border-radius: 5px;
font-size: 15px;
padding: 5px;
margin-right: 20px;
${mobile({ height: "50%" })}
`;
const MenuItem = styled.div`
margin-left: 25px;
margin-top: 3px;
font-size: 18px;
font-weight: 600;
color: #0a6596e6;
cursor: pointer;
justify-content: space-between;
${mobile({ fontSize: "13px", marginLeft: "10px" })}
`;
const Navbar = () => {
const { user, logoutHandler, isLoggedIn } = useContext(AuthContext);
console.log(user)
return (
<Parent>
<Container>
<Wrapper>
<Left>
<Link to={"/"}>
<Logo>audiobae</Logo>
</Link>
</Left>
<SearchContainer style={{ color: "gray", fontSize: 14 }}>
<Input placeholder="Search for products, brands and more" />
<Search style={{ fontSize: "30px" }} />
</SearchContainer>
<Right>
<Language style={{ marginLeft: "5px", marginTop: "3px" }}>
<TranslateOutlined />
</Language>
{console.log(isLoggedIn)}
{isLoggedIn ? (
<>
<MenuItem>{user?.email}</MenuItem>
<MenuItem onClick={logoutHandler}>Logout</MenuItem>
</>
) : (
<>
<Link to={"/register"} style={{ textDecoration: "none" }}>
<MenuItem>Register </MenuItem>
</Link>
<Link to={"/login"} style={{ textDecoration: "none" }}>
<MenuItem>Login</MenuItem>
</Link>
</>
)}
<MenuItem>
<Link to={"/cart"}>
<Badge badgeContent={cart?.total_items} color="primary">
{console.log(cart)}
<MenuItem>
<ShoppingCartOutlined />
</MenuItem>
</Badge>
</Link>
</MenuItem>
</Right>
</Wrapper>
</Container>
</Parent>
);
};
export default Navbar;
try it
<AuthContext.Provider value={{user,logoutHandler,isLoggedIn}}>
<Navbar/>
</AuthContext.Provider>

Adding A button before the previousLabel Props and after the nextLabel Props in React-Paginate Not Working

Please I needed to add a button before the previousLabel property details and after the nextLabel prop details in React-Paginate but what I have below is not working. I have also tried to read the documentation and check all the prop details but still couldn't achieve the result below.
I want a first button to come before one button and a last button to come after the next button.
what the code below looks like above.
what I want to achieve below
```
import React, { useState, useEffect } from 'react'
import axios from 'axios'
import ReactPaginate from 'react-paginate';
import './styles.css'
export default function App() {
const [postsPerPage] = useState(5);
const [offset, setOffset] = useState(1);
const [posts, setAllPosts] = useState([]);
const [pageCount, setPageCount] = useState(0)
const getPostData = (data) => {
return (
data.map(post => <div className="container" key={post.id}>
<p>User ID: {post.id}</p>
<p>Title: {post.title}</p>
</div>)
)
}
const getAllPosts = async () => {
const res = await axios.get(`https://jsonplaceholder.typicode.com/posts`)
const data = res.data;
const slice = data.slice(offset - 1 , offset - 1 + postsPerPage)
// For displaying Data
const postData = getPostData(slice)
// Using Hooks to set value
setAllPosts(postData)
setPageCount(Math.ceil(data.length / postsPerPage))
}
const handlePageClick = (event) => {
const selectedPage = event.selected;
setOffset(selectedPage + 1)
};
useEffect(() => {
getAllPosts()
}, [offset])
return (
<div className="main-app">
{/* Display all the posts */}
{posts}
{/* Using React Paginate */}
<ReactPaginate
previousLabel={"previous"}
nextLabel={"next"}
breakLabel={"..."}
breakClassName={"break-me"}
pageCount={pageCount}
onPageChange={handlePageClick}
containerClassName={"pagination"}
subContainerClassName={"pages pagination"}
activeClassName={"active"} />
</div>
);
}
```
Below is the css
.main-app {
margin: 2% 10%;
border: 1px ridge #464141;
padding: 5%;
font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;
font-size: 20px;
color: #464141;
}
.container {
border-bottom: #fff 2px ridge;
}
.pagination {
margin-top: 45px;
margin-left: -40px;
display: flex;
list-style: none;
outline: none;
}
.pagination>.active>a {
background-color: #47ccde;
color: #fff;
}
.pagination>li>a {
border: 1px solid #47ccde;
padding: 5px 10px;
outline: none;
cursor: pointer;
}
.pagination>li>a, .pagination>li>span {
color: #47ccde;
background-color: azure;
}

Strange stuff with useState, useEffect and fetch

I'm trying to fetch some data inside useEffect and when the data is received I want to set a certain state with useState. Data correctly returns from the server. However this doesn't work. Here's the code:
const [sharingLink, setSharingLink] = React.useState(null);
React.useEffect(() => {
client.query({
query: queryGetReferalData
}).then(result => {
console.warn(result); // correct response
setSharingLink(result.data.referralsystem.shareUrl);
console.warn(sharingLink); // null
});
}, []);
Here's the whole component:
import React from 'react';
import styled from 'styled-components';
import { i18n } from 'Helpers';
import { Button } from './Button';
import { ButtonLink } from './ButtonLink';
import { Heading } from './Heading';
import { Input } from './Input';
import Copy from './icons/Copy';
import Facebook from './icons/Facebook';
import Twitter from './icons/Twitter';
import WhatsApp from './icons/WhatsApp';
import client from '#client/apollo';
import queryGetReferalData from './schemas/queryGetReferalData.graphql';
const Root = styled.div`
padding: 48px;
padding-top: 32px;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0px 10px 30px rgba(27, 50, 85, 0.1);
border-radius: 4px;
background-color: #FFFFFF;
`;
const Pane = styled.div`
`;
const Row = styled.div`
display: flex;
& > * + * {
margin-left: 10px;
}
`;
export const Form = () => {
const [sharingLink, setSharingLink] = React.useState(null);
const facebookSharingLink =
sharingLink && `https://www.facebook.com/sharer/sharer.php?${encodeURIComponent(sharingLink)}`;
const twitterSharingLink =
sharingLink && `http://www.twitter.com/share?url=${encodeURIComponent(sharingLink)}`;
const whatsAppSharingLink =
sharingLink && `whatsapp://send?text=${encodeURIComponent(sharingLink)}`;
React.useEffect(() => {
client.query({
query: queryGetReferalData
}).then(result => {
console.warn(result);
setSharingLink(result.data.referralsystem.shareUrl);
console.warn(sharingLink);
});
}, []);
return (
<Root>
<Pane>
<Heading>
{ i18n._('Your invitational link') }
</Heading>
<Row>
<Input disabled={sharingLink === null} value={sharingLink} />
<Button icon={<Copy />}>
{ i18n._('COPY') }
</Button>
</Row>
</Pane>
<Pane>
<Heading>
{ i18n._('Or share via social') }
</Heading>
<Row>
<ButtonLink
backgroundColor='#5A79B5'
icon={<Facebook />}
href={facebookSharingLink}
>
{ i18n._('Facebook') }
</ButtonLink>
<ButtonLink
backgroundColor='#52A6DB'
icon={<Twitter />}
href={twitterSharingLink}
>
{ i18n._('Twitter') }
</ButtonLink>
<ButtonLink
backgroundColor='#0DC455'
icon={<WhatsApp />}
href={whatsAppSharingLink}
>
{ i18n._('WhatsApp') }
</ButtonLink>
</Row>
</Pane>
</Root>
);
};
The component also renders like sharingLink is null.
Why is this happening?
What do I do to make this work?
I had some code that was adding to the DOM in the parent component. When I remove it, everything works.
Adding to the DOM in the component, doesn't matter if it's into useEffect or not, somehow messes up hooks even though you add HTML to something completely unrelated to react I guess.
I had this structure:
<body>
<div id="page">
<div id="root">
<CustomReactElement />
</div>
</div>
<body>
The code inside CustomReactElement was adding markup to the 'page'. I changed the code from setting an innerHTML to appendChild() and everything worked.

React Context API returns undefined

I'm quite new to React, and i'm trying to make a ToDoList. I have a Modal with a submit button that when pressed should add a ToDoItem. But since i didn't want to prop drill my way through this i wanted to use the Context API. The Context API confuses me quite a bit, maybe i'm just a moron, but i have a hard time understanding why i have to make a hook and pass that as the value in the provider. I thought that in the ToDoContext that i already defined the default value as a empty array, so i just did it again.
In the console at line 62, which is my initial render it says that it's undefined, after the pressing the Add ToDo I get the same message.
App.jsx
import React, { useState } from "react";
import { render } from "react-dom";
import { ThemeProvider } from "emotion-theming";
import { defaultTheme } from "./theme";
import { Global, css } from "#emotion/core";
import Header from "./components/Header";
import ToDoList from "./components/ToDoList";
import AddBtn from "./components/AddBtn";
import ToDoContext from "./ToDoContext";
const App = () => {
const [toDoItems] = useState([]);
return (
<>
{/*Global styling*/}
<Global
styles={css`
* {
margin: 0;
padding: 0;
box-sizing: border-box;
list-style: none;
text-decoration: none;
}
`}
/>
{/*App render start from here*/}
<ThemeProvider theme={defaultTheme}>
<ToDoContext.Provider value={toDoItems}>
<Header />
<main>
<ToDoList />
<AddBtn />
</main>
</ToDoContext.Provider>
</ThemeProvider>
</>
);
};
render(<App />, document.getElementById("root"));
ToDoContext.jsx
import { createContext } from "react";
const ToDoContext = createContext([[], () => {}]);
export default ToDoContext;
AddBtn.jsx
import React, { useState, useContext } from "react";
import { css } from "emotion";
import Modal from "../Modal";
import ToDoContext from "../ToDoContext";
const BtnStyle = css`
position: fixed;
bottom: 0;
right: 0;
cursor: pointer;
display: block;
font-size: 7rem;
`;
const ModalDiv = css`
position: fixed;
left: 50%;
background-color: #e6e6e6;
width: 60%;
padding: 20px 20px 100px 20px;
display: flex;
flex-direction: column;
align-items: center;
max-width: 400px;
height: 50%;
transform: translate(-50%, -50%);
border-radius: 20px;
top: 50%;
`;
const textareaStyle = css`
resize: none;
width: 100%;
height: 200px;
font-size: 1.25rem;
padding: 5px 10px;
`;
const timeStyle = css`
font-size: 3rem;
display: block;
`;
const modalSubmit = css`
width: 100%;
font-size: 3rem;
cursor: pointer;
margin-top: auto;
`;
const Label = css`
font-size: 2rem;
text-align: center;
display: inline-block;
margin-bottom: 50px;
`;
const AddBtn = () => {
const [showModal, setShowModal] = useState(true);
const [time, setTime] = useState("01:00");
const [toDoItems, setToDoItems] = useContext(ToDoContext);
console.log(toDoItems);
return (
<>
<div className={BtnStyle} onClick={() => setShowModal(!showModal)}>
<ion-icon name="add-circle-outline"></ion-icon>
</div>
{showModal ? (
<Modal>
<div className={ModalDiv}>
<div>
<label className={Label} htmlFor="time">
Time
<input
className={timeStyle}
type="time"
name="time"
value={time}
onChange={(e) => setTime(e.target.value)}
/>
</label>
</div>
<label className={Label} htmlFor="desc">
Description
<textarea
className={textareaStyle}
name="desc"
placeholder={`Notify yourself this message in ${time}`}
></textarea>
</label>
<button
className={modalSubmit}
onClick={() => {
setToDoItems(
toDoItems.push({
time,
})
);
}}
>
Add ToDo
</button>
</div>
</Modal>
) : null}
</>
);
};
export default AddBtn;
There are few issues in your code to fix:
useState returns a value and a setter. With this line of code, const [toDoItems] = useState([]);, you are just passing an empty array to your context.
So do this:
const toDoItems = useState([]);
In your ToDoContext.js, just pass an empty array as argument (initial value)
const ToDoContext = createContext([]);
Working copy of your code is here. (see console logs)
Also, I noticed that you are pushing the todo in setTodoItems in AddBtn.js.
Don't do this:
onClick={() => {
setToDoItems(
toDoItems.push({
time
})
);
}}
Do this:
onClick={() => {
setToDoItems(
toDoItems.concat([
{
time
}
])
);
}}

Resources