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
Related
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.
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
We are making the necessary consent for membership registration with React. However, it is up to agreeing to the checkbox, but it does not work properly because it is re-rendered when the button is clicked. Any help would be appreciated.
enter code here
const [disabled, setDisabled] = useState('disabled');
const [agree1, setAgree1] = useState(false); //회원정보 동의
const [agree2, setAgree2] = useState(false); //개인정보 수집 및 이용동의
const [agree3, setAgree3] = useState(false); //위치정보 동의
const [total, settotal] = useState(false); //전체 동의
const [email, setemail] = useState("");
const buttonState = useCallback(() => {
if((agree1===true)&&(agree2===true)&&(agree3===true)){
settotal(true);
setDisabled('');
}
else {
setDisabled('disabled');
}
},[agree1,agree2,agree3,total]);
useEffect(() => {
buttonState();
}, [buttonState])
const totalchange = () => {
if(total ===true) { //전체동의가 true라면 다시 클릭 했을때 전부 unchecked
settotal(!total);
setAgree1(!agree1);
setAgree2(!agree2);
setAgree3(!agree3);
} else{ //그외(하나만 체크되 있거나 아무것도 없다면) 전부 checked로 만듬
settotal(true);
setAgree1(true);
setAgree2(true);
setAgree3(true);
setDisabled('');
}
}
const clickFunction = () => {
axios.get(`/signup/authNum?email=${email}`)
.then(res => {
if(window.confirm("인증번호 전송이 완료되었습니다")){
history.push({
pathname : '/registerauth',
state : {state : res.data}
})
}
})
.catch(err => {console.log(err)})
}enter code here
Sorry for being awkward because this is my first question on stack-overflow
Why are you using the callback for the button click and why are you calling that function in useEffect?
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}`)
})
},[]);
So I'm using useEffect hook to fetch my data from database and after I get that data I want to set it as useState for title and postBody, but it doesn't work, because useEffect hook runs "last", how can I fix it?
Code:
const [cPost, setCPost] = useState([]);
const postId = id.match.params.id;
useEffect(() => {
axios.get('http://localhost:5000/posts/'+postId)
.then(posts => {
setCPost(posts.data);
console.log("SAS");
})
}, []);
const [title, setTitle] = useState(cPost.title);
const [postBody, setPostBody] = useState(cPost.postBody);
As a temporary and quick solution, you can use such workaround:
const [cPost, setCPost] = useState();
const [title, setTitle] = useState();
const [postBody, setPostBody] = useState();
const postId = id.match.params.id;
useEffect(() => {
axios.get('http://localhost:5000/posts/'+postId)
.then(post => {
setCPost(post.data);
console.log("SAS");
})
}, []);
useEffect(() => {
if(cPost) {
setTitle(cPost.title);
setPostBody(cPost.postBody);
}
}, [cPost]);
Or the second option:
const [cPost, setCPost] = useState();
const [title, setTitle] = useState();
const [postBody, setPostBody] = useState();
const postId = id.match.params.id;
useEffect(() => {
axios.get('http://localhost:5000/posts/'+postId)
.then(post => {
setCPost(post.data);
setTitle(post.title);
setPostBody(post.postBody);
console.log("SAS");
})
}, []);
But in the future I would recommend doing side effects like API requests and others using special libraries or create hook for making API requests.
For example redux-saga or redux-thunk.
And use a state manager like redux or mobx.
P.S. and consider whether you need to store the title and body separately in the component state. I have a strong suspicion that you have no need for it.