I made this useEffect code that works good in a screen:
useEffect(() => {
getDatasFromId(searchId)
.then((data) => {
const returnObject = {
next: data.next,
items: data.results.map(item => ({ name: item.name, url: item.url }))
};
setHasNext(returnObject.next);
setDataToDisplay(returnObject.items);
});
}, [searchId]);
But now, I made some modification and the API call is running without return (no error or whatever). My new code is this:
useEffect(() => {
const apiUrl = getApiUrl(searchId);
console.log("API URL : ", apiUrl);
getDatas(apiUrl)
.then((data) => {
console.log("We get some data : ", data.results );
const returnObject = buildDataObject(data);
console.log("returnObject : ", returnObject);
setDataToDisplay(returnObject.items);
returnObject.next !== null && loadMoreApiDatasIf(returnObject.next);
});
}, [searchId]);
I don't see the error in the new code.
Related
I'm trying to keep session stayed logged in after refreshing the browser. The user data that is being fetched is not rendering after being fetched. The console is saying "Cannot read properties of undefined (reading 'user'). This is my code for the login/sign up page.
The data I'm trying to access is in the picture below:
(Auth.js)
const Auth = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const [isSignup, setIsSignup] = useState(false);
const [inputs, setInputs] = useState({
name: "",
username: "",
email: "",
password: ""
})
const handleChange = (e) => {
setInputs(prevState => {
return {
...prevState,
[e.target.name]: e.target.value
}
})
}
const sendRequest = async (type = '') => {
const res = await axios.post(`/user/${type}`, {
name: inputs.name,
email: inputs.email,
username: inputs.username,
password: inputs.password,
}).catch(error => console.log(error))
const data = await res.data;
console.log(data)
return data;
}
const handleSubmit = (e) => {
e.preventDefault()
console.log(inputs)
if (isSignup) {
sendRequest("signup")
.then((data) => {
dispatch(authActions.login());
localStorage.setItem('userId', data.user._id);
navigate("/posts");
});
} else {
sendRequest("login")
.then((data) => {
dispatch(authActions.login());
localStorage.setItem('userId', data.user._id);
navigate("/posts");
});
}
}
Redux store file
const authSlice = createSlice({
name: "auth",
initialState: { isLoggedIn: false },
reducers: {
login(state) {
state.isLoggedIn = true
},
logout(state) {
state.isLoggedIn = false
}
}
})
export const authActions = authSlice.actions
export const store = configureStore({
reducer: authSlice.reducer
})
Chaining promises using .then() passes the resolved value from one to the next. With this code...
sendRequest("...")
.then(() => dispatch(authActions.login()))
.then(() => navigate("/posts"))
.then(data => localStorage.setItem('token', data.user))
You're passing the returned / resolved value from navigate("/posts") to the next .then() callback. The navigate() function returns void therefore data will be undefined.
Also, your redux action doesn't return the user so you can't chain from that either.
To access the user data, you need to return it from sendRequest()...
const sendRequest = async (type = "") => {
try {
const { data } = await axios.post(`/user/${type}`, { ...inputs });
console.log("sendRequest", type, data);
return data;
} catch (err) {
console.error("sendRequest", type, err.toJSON());
throw new Error(`sendRequest(${type}) failed`);
}
};
After that, all you really need is this...
sendRequest("...")
.then((data) => {
dispatch(authActions.login());
localStorage.setItem('userId', data.user._id);
navigate("/posts");
});
Since you're using redux, I would highly recommend moving the localStorage part out of your component and into your store as a side-effect.
Hi so I'm trying to grab some json from an api and then populate a table, pretty simple stuff.
What's happening is that I can see the "tableData" state being updated as each new row comes in, I'm also logging every time "tableData" is updated, yet maybe .5 seconds after its all done my "tableData" is empty again (check console screenshots)
const [bigChartData, setbigChartData] = React.useState("data1");
const [tableData, setTableData] = React.useState([]);
const setBgChartData = (name) => {
setbigChartData(name);
};
const getData = () => {
axios.get("URL")
.then(res => {
const data = res.data.items.forEach(item => {
setTableData(oldData => [...oldData, {
data: [
{ text: item.title },
{ text: "asd" + item.url },
{ text: "some links..." }
]
}]);
});
})
.catch(err => console.log(err));
setTimeout(function () {
console.log(tableData);
}, 3000);
}
useEffect(() => {
getData();
}, []);
useEffect(() => {
console.log("Table data updated:");
console.log(tableData);
}, [tableData]);
I think you should not iterate through each row inside getData() method instead try following code
const getData = () => {
axios.get("URL")
.then(res => {
const data = res.data.items.map(item => {
return{
data: [
{ text: item.title },
{ text: "asd" + item.url },
{ text: "some links..." }
]
};
});
setTableData(data)
}).catch(err => console.log(err));
}
or if you have already some data in tableData then
setTableData([...tableData, data])
I am trying to display the borders of a country from restcountries api (https://restcountries.eu/) as clickable buttons.
this is how I try to build the url for the api
mounted() {
axios
.get(this.urlDetail)
.then(response => (
this.details = response.data[0]
))
this.borders = this.details.borders.join(";");
this.urlBorders = "https://restcountries.eu/rest/v2/alpha?codes=" + this.borders;
fetch(this.urlBorders)
.then(res => res.json())
.then(data => this.bordersData = data)
the problem is, that the details array is empty at that moment. When I reload the page, the data is fetched correctly.
I tried to:
use beforeMount()
use a isFetching boolean
get the data with #click-function
tried is with these function in mounted():
document.onreadystatechange = () => {
if (document.readyState == "complete") {
console.log('Page completed with image and files!')
}
}
this is my data:
data() {
return {
isFetching: true,
urlDetail: 'https://restcountries.eu/rest/v2/name/' + this.$route.params.countryName,
details: [],
borders: "",
urlBorders: "",
bordersData: []
}
this is the relevant html snipped to display the buttons:
<p><strong>Border Countries:</strong><button class="border-button" v-for="border in bordersData"><router-link :to="{ name: 'border', params: {borderName: border.name}}">{{ border.name }}</router-link></button></p>
thanks for helping!
Try to wait for responses:
methods: {
async getBorders() {
await axios
.get(this.urlDetail)
.then((response) => (this.details = response.data[0]));
},
setBorders() {
this.borders = this.details.borders.join(";");
this.urlBorders =
"https://restcountries.eu/rest/v2/alpha?codes=" + this.borders;
},
async getDets() {
await axios
.get(this.urlBorders)
.then((response) => (this.bordersData = response.data));
},
},
},
async mounted() {
await this.getBorders();
this.setBorders();
await this.getDets();
},
I've been building an app with Firebase & React Native primarily using Firestore. I started to use Firestore and its been great, but for some reason when writing to Firestore, it is only working on the first attempt (when i remove the app, rebuild, and perform my write).
I tried to do the exact same thing except write to Firestore and everything works as expected.
I am also receiving no error!
Here is what I am doing:
export const addBrandProduct = (postObj) => {
return () => {
firebase
.firestore()
.collection('brandProducts')
.add(postObj)
.then((docRef) => {
console.log("Document written with ID: ", docRef.id);
Actions.categories();
})
.catch(error => {
console.error("Error adding document: ", error);
});
};
};
For more of a reference, here is my component code that calls addBrandProduct()
onUploadImages = () => {
let photo =
Platform.OS === 'ios'
? this.state.images.map(img => img.uri.replace('file://', ''))
: this.state.images.map(img => img.uri);
photo.forEach((image, i) => {
const sessionId = new Date().getTime();
const Blob = RNFetchBlob.polyfill.Blob;
const fs = RNFetchBlob.fs;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
let uploadBlob = null;
let mime = 'image/jpg';
const imageRef = firebase
.storage()
.ref('brandProducts/')
.child(`${this.props.userData.uid}`)
.child(`${sessionId}-${i}`);
fs.readFile(image, 'base64')
.then(data => {
return Blob.build(data, {type: `${mime};BASE64`});
})
.then(blob => {
uploadBlob = blob;
return imageRef.put(blob, {contentType: mime});
})
.then(() => {
uploadBlob.close();
return imageRef.getDownloadURL();
})
.then(url => {
//if this is the last uploaded image, post data to db
if (i === this.state.images.length - 1) {
const urls = {
...this.state.urls,
[i]: url,
};
const postObj = {
...this.state.postObj,
urls: urls,
};
this.props.addBrandProduct(postObj);
} else {
this.setState({
urls: {
...this.state.urls,
[i]: url,
},
});
}
})
.catch(error => {
console.log(error);
});
});
};
Basically, I am uploading a maximum of 3 images along with some data for it. In order to ensure I am uploading them all prior to adding the post data (writing to firestore) I am using a forEach and on the last upload, when it completes, I am calling the action to write the post data.
Edition
Hum addBrandProduct is a function that create another function.
So when you call this.props.addBrandProduct(postObj) nothing is sent to firestore, you just create a new function that should be called.
Maybe you can go out this stuff and call firebase directly, ensuring that everything works and then go back to the redux way if you still want to use it. I also make it parallelized instead of sequentials. Hope it help, hard to find the real problem when it can come from anywhere.
onUploadImages = () => {
let photo = Platform.OS === 'ios'
? this.state.images.map(img => img.uri.replace('file://', ''))
: this.state.images.map(img => img.uri);
Promise.all( photo.map( image => {
const sessionId = new Date().getTime();
const Blob = RNFetchBlob.polyfill.Blob;
//This is kind useless
//const fs = RNFetchBlob.fs;
//This is not used
//window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
//This is not adviced
//window.Blob = Blob;
let uploadBlob = null;
let mime = 'image/jpg';
const imageRef = firebase
.storage()
.ref('brandProducts/')
.child(`${this.props.userData.uid}`)
.child(`${sessionId}-${i}`);
return fs.readFile(image, 'base64')
.then(data => {
return RNFetchBlob.polyfill.Blob.build(data, {type: `${mime};BASE64`});
})
.then(blob => {
uploadBlob = blob;
return imageRef.put(blob, {contentType: mime});
})
.then(() => {
uploadBlob.close();
return imageRef.getDownloadURL();
});
))
.then( results => {
//results is, here, [ urlFromFirst, urlFronSecond, ...]
const urls = { ...this.state.urls};
results.forEach( (r, i) => urls[i] = r );
const postObj = {
...this.state.postObj,
urls
};
return firebase
.firestore()
.collection('brandProducts')
.add(postObj)
})
.then( docRef => {
console.log("Document written with ID: ", docRef.id);
})
.catch(error => {
console.error(error);
});
};
So, I'm simply trying to set state in my react app. Simply get data from Axios, and then set state. But no matter what I do, the state will not set. I've tried putting it in a callback since it's async and putting it my component did mount and component did update alas nothing. any pointers?
class App extends Component {
componentDidUpdate() {}
constructor(props) {
super(props);
this.state = {
Catogories: [
"Business",
"Entertainment",
"General",
"Health",
"Science",
"Sports",
"Technology"
],
CatPics: [],
TopStories: [],
Selection: [],
Sources: [],
selected: false
};
}
GeneratePic = () => {
this.state.Catogories.forEach(Catogory => {
axios
.get(
"https://api.pexels.com/v1/search?query=" +
Catogory +
"&per_page=15&page=1",
{
Authorization:
"563492ad6f91700001000001d33b5d31a9a145b78ee67e35c8e6c321"
}
)
.then(res => {
var object = { Catogory: res.photos[0].src.large2x };
this.state.CatPics.push(object);
});
});
};
dump = x => {
this.setState({ TopStories: x }, console.log(this.state.TopStories));
};
TopStories = () => {
console.log("working");
axios
.get(
"https://newsapi.org/v2/top-headlines?country=us&apiKey=91bec895cf8d45eaa46124fb19f6ad81"
)
.then(res => {
console.log(res);
const data = res.data.articles;
console.log(data);
this.dump(data);
});
};
You are doing two things wrong.
Don't mutate the state
Don't do async actions inside loop and then use same loop variable inside async callback because at that point in time, loop variable will have some other value and not the respective iteration category.
GeneratePic = async () => {
const promises = this.state.Catogories.map(Catogory => {
return axios
.get(
"https://api.pexels.com/v1/search?query=" +
Catogory +
"&per_page=15&page=1",
{
Authorization:
"563492ad6f91700001000001d33b5d31a9a145b78ee67e35c8e6c321"
}
)
.then(res => {
return res.photos[0].src.large2x;
});
});
let photos = await Promise.all(promises);
photos = this.state.Catogories.map((cat, index) => ({ [cat]: photos[index] }));
this.setState({ CatPics: photos });
};
getPics = cat => {
return axios
.get(
"https://api.pexels.com/v1/search?query=" +
cat +
"&per_page=15&page=1",
{
Authorization:
"563492ad6f91700001000001d33b5d31a9a145b78ee67e35c8e6c321"
}
)
.then(res => {
return { [cat]: res.photos[0].src.large2x };
});
}
GeneratePic = async () => {
const promises = this.state.Catogories.map(Catogory => {
this.getPics(Catogory);
});
let photos = await Promise.all(promises);
this.setState({ CatPics: photos });
};
This should work.
Dont Mutate the state.
GeneratePic = () => {
this.state.Catogories.forEach(async Catogory => {
await axios
.get(
"https://api.pexels.com/v1/search?query=" +
Catogory +
"&per_page=15&page=1", {
Authorization: "563492ad6f91700001000001d33b5d31a9a145b78ee67e35c8e6c321"
}
)
.then(res => {
var object = { Catogory: res.data.photos[0].src.large2x };
const cPics = [...this.state.CatPics];
cPics.push(object);
this.setState({
CatPics: cPics
})
});
});
};