How to get object data and push an array in React? - javascript

I have an endpoint that returns an object. The object is:
{
"id": "669f8",
"creation_date": "2022-01-13 10:33:06.046652+01:00",
"case_type": "Summary",
"process_types": "",
"case_id": "ad23423s",
"current_stage": "",
"current_stage_name": "",
"consolidation": "None",
"last_change_date": "2022-01-14 14:35:17.563449+01:00",
"status": 1,
"assign": "Yes"
}
I want to display it in my React project.
Firstly I want to take object fields, and then the values.
I wrote this code:
class DetailsPage extends React.Component<DetailProps> {
async getData() {
const data = await Dependencies.backend.getList(this.props.url);
if (data) {
return data;
}
return [];
}
render() {
const data = this.getData()
const fields: string[][] = []
const test: any[] = []
data.then((val: any) =>
fields.push(Object.keys(val))
// console.log(val)
) .catch(err => console.log("There was an error:" + err))
console.log("testeststt")
console.log(fields)
return (
<div>
<h1>Hoi!</h1>
</div>
);
}
}
The console.log(fields) returns
[]
And when I open the array it shows
But I can't get the 0th row.
How can I get and push another array or something?

The reason for this is that the render function only renders out the UI. It is not supposed to make asynchronous stuff. Since, you need to invoke the API call when the component mounts, you can do it in componentDidMount and when you have data, update it in state.
This way, on the initial render, you will have 0 items in the data. When you update the state, it will re-render the component and then you will have items in your data.
You can do something like the following:
componentDidMount() {
this.getData()
}
async getData() {
const data = await Dependencies.backend.getList(this.props.url);
this.setState({ data: data ?? [] })
}
render() {
const { data } = this.state;
console.log(data)
}

Related

Unable to fetch data onto a dynamic page in Next JS

I am trying to create a dynamic page in Nextjs app, but continue to get an error:
./somepage/[id].js (20:25) # map
Unhandled Runtime Error
TypeError: Cannot read properties of undefined (reading 'map')
So basically what I did to recreate the issue was
I set up a dynamic page [id].js and tried fetching data from a helper file using getStaticProps and getStaticPaths as shown below:
// "./somepage/[id].js"
import {postData} from "./lib/helper"
function classNames(...classes) {
return classes.filter(Boolean).join(" ");
}
export default function Post({ posts }) {
console.log(posts); //is "undefined".
console.log(postData) // logs out the data successfully
return (
<>
{posts.map((post) =>{
<div key = {post.id}>
Hello {post.author}, This is your title: {post.title}
</div>
})}
</>
);
}
export async function getStaticPaths({ params }) {
const { id } = params;
const posts = postData(id);
const paths = posts.map((item) => {
params: {
id: item.id.toString();
}
return {
paths,
fallback: false,
};
});
}
export async function getStaticProps() {
const posts = postData();
console.log(posts); //Logs nothing to the console
return {
props: { posts }, //This prop `posts` renders as undefined on the page.
};
}
The helper file is a function that returns an array of objects, and filters through the array if the array id matches the id from the params as shown below:
// "./lib/helper.js"
export function postData(id) {
const data = [{
...
...
}]
if(id){
return data.filter((item) => {
return item.id === id;
});
}
return data;
}
The issue I am having is that if I console log data from the helper file from within getStaticProps as shown above, I don't get anything back in the console... nothing, but get the above error in the browser. However, logging postData (from the helper.js file) inside of the dynamic page itself returns data as expected, but logging the prop posts that I passed in the getStaticProps comes out as undefined . My version of NextJs is v.13.. could the version be the reason why i couldn't pass data as props onto the page?
For me it is supposed to be something like that :
export async function getStaticPaths() {
const posts = postData();
const paths = posts.map((item) => {
params: {
id: item.id.toString();
}
});
return {
paths,
fallback: false,
};
}
export async function getStaticProps({ params }) {
const { id } = params;
const posts = postData(id);
return {
props: { posts },
};
}

Nuxt: how to load data to store on app initialization

I am aiming to have a state in my Vuex store which gets populated on initial app load with data from an external API as follows:
import axios from 'axios'
export const state = () => ({
airports: [],
pairing: {
departure: null,
arrival: null
},
loading: false
})
export const getters = {
getAirports: (state) => {
return state.airports
}
}
export const mutations = {
SET_AIRPORTS(state, payload) {
state.airports = payload
},
SET_LOADING(state, payload) {
state.loading = payload
},
SET_AIRPORT(state, { airport, type }) {
state.pairing[type] = airport
},
CLEAR_AIRPORT(state, type) {
state.pairing[type] = null
}
}
export const actions = {
loadAirports({ commit }) {
commit('SET_LOADING', true)
axios.get('https://raw.githubusercontent.com/jpatokal/openflights/master/data/airports.dat')
.then(response => {
// Get each row of data from the source
const rows = response.data.split('\n');
// Convert data from row to object
const airports = rows.map(row => {
// Parse the comma-separated fields from the line by using
const fields = row.split(',')
.map(x => x.replace(/(^"|"$)/g, ''));
return {
id: fields[0],
name: fields[1],
city: fields[2],
country: fields[3],
iata: fields[4],
icao: fields[5],
longitude: fields[6],
latitude: fields[7],
};
});
commit('SET_AIRPORTS', airports)
commit('SET_LOADING', false)
})
},
}
Usually I would just dispatch the loadAirports action in the App.vue when working with Vue.js standalone. However, as I am building my app in Nuxt.js I cannot seem to figure out how to load the data to my state without dispatching this method in every page I create but rather just once on app load.
Any suggestions?
If you have an action called nuxtServerInit in universal mode, Nuxt will call it with the Nuxt context. You can use this function to load data or dispatch other actions:
const actions = {
nuxtServerInit({ dispatch }, ctx) {
dispatch('loadAirports');
}
}
Note that nuxtServerInit is only called server side (or during compile-time if statically generating). You can implement a similar nuxtClientInit by creating a client plugin that immediately dispatches to the store.
https://nuxtjs.org/docs/directory-structure/store/#the-nuxtserverinit-action
This is actually quite simple to do in NuxtJs.
First of all define your initial state:
export const state = () => ({
airports: [],
})
Since Nuxt gives access to nuxtServerInit inside of your file you can do this:
//NOTE this only works when mode is set to universal inside of your nuxt config
export const actions = {
async nuxtServerInit({ commit }) {
const data = await this.$axios.$get(`your-api`)
// you can do all of your logic here before commiting
commit('setAirports', data)
}
}
than all you have left to do is create a mutatation to fill the state with your data
export const mutations = {
setAirports(state, payload) {
state.airports.push(...payload)
},
}

Can't use new redux state right after fetching a response from Socket.IO

I have a function "sendMessage" in React class:
class MessageForm extends React.Component {
...
sendMessage = async () => {
const { message } = this.state;
if (message) {
this.setState({ loading: true });
if (this.props.isPrivateChannel === false) {
socket.emit("createMessage", this.createMessage(), (response) => {
this.setState({ loading: false, message: "", errors: [] });
});
} else {
if (this.state.channel && this.state.channel._id === undefined) {
socket.emit("createChannelPM", this.state.channel, async (response) => {
const chInfo = { ...response, name: this.props.currentChannel.name };
console.log("chInfo : ", chInfo);
await this.props.setCurrentChannel(chInfo).then((data) => {
if (data) {
console.log("data : ", data);
console.log("this.props.currentChannel : ", this.props.currentChannel);
}
});
});
}
...
function mapStateToProps(state) {
return {
isPrivateChannel: state.channel.isPrivateChannel,
currentChannel: state.channel.currentChannel,
};
}
const mapDispatchToProps = (dispatch) => {
return {
setCurrentChannel: async (channel) => await dispatch(setCurrentChannel(channel)),
}
};
Here, in sendMessage function, I retrieve "response" from socket.io, then put this data into variable "chInfo" and assign this to Redux state, then print it right after assinging it.
And Redux Action function, "setCurrentChannel" looks like:
export const setCurrentChannel = channel => {
return {
type: SET_CURRENT_CHANNEL,
payload: {
currentChannel: channel
}
};
};
Reducer "SET_CURRENT_CHANNEL" looks like:
export default function (state = initialState, action) {
switch (action.type) {
case SET_CURRENT_CHANNEL:
return {
...state,
currentChannel: action.payload.currentChannel
};
...
The backend Socket.io part look like (I use MongoDB):
socket.on('createChannelPM', async (data, callback) => {
const channel = await PrivateChannel.create({
...data
});
callback(channel)
});
The console.log says:
Problem : The last output, "this.props.currentChannel" should be same as the first output "chInfo", but it is different and only print out previous value.
However, in Redux chrome extension, "this.props.currentChannel" is exactly same as "chInfo":
How can I get and use newly changed Redux states immediately after assinging it to Redux State?
You won't get the updated values immediately in this.props.currentChannel. After the redux store is updated mapStateToProps of MessageForm component is called again. Here the state state.channel.currentChannel will be mapped to currentChannel. In this component you get the updated props which will be accessed as this.props.currentChannel.
I believe you want to render UI with the latest data which you which you can do.

problem data recovery with axios and vue cal (scheluder)

I need to get data with axios and send them to my calendar with the 'splitDays' table and I have to change the variable name of my data to put "class" and "label"
I can recover my data but when I leave the axios I go to undefined
data() {
return {
splitDays:[], // :splitDays
};
},
mounted() {
axios
.get(`${process.env.*****}/users?role=***&active=***`)
.then(response => ( this.users = response.data,
console.log(this.users)
))
console.log(this.users)
/*
for (let splitDayIndex in mySplitDays){
let splitDay= mySplitDays[splitDayIndex]
splitDay.class = splitDay.lastname
splitDay.label = splitDay.lastname
mySplitDays[splitDayIndex]=splitDay
}
*/
},
I'm not sure I understand what you mean by when I leave the axios I go to undefined, but your second console.log(...) will be executed before your axios call finishes. Try with:
data() {
return {
splitDays:[], // :splitDays
};
},
async mounted() {
let response = await axios
.get(`${process.env.AFFECTIT_API}/users?role=Collaborateur&active=1`)
this.users = response.data
console.log(this.users)
/*
for (let splitDayIndex in mySplitDays){
let splitDay= mySplitDays[splitDayIndex]
splitDay.class = splitDay.lastname
splitDay.label = splitDay.lastname
mySplitDays[splitDayIndex]=splitDay
}
*/
},

Vue js2 vuex update a form v-model values

I have setup vuex and i would like to later fetch the data and update my form model but this fails
In my vuex
//state
const state = {
profile: [],
}
//getter
const getters = {
profileDetails: state => state.profile,
}
//the actions
const actions = {
getProfileDetails ({ commit }) {
axios.get('/my-profile-details')
.then((response) => {
let data = response.data;
commit(types.RECEIVED_USERS, {data});
},
);
}
}
const mutations = {
[types.RECEIVED_USERS] (state, { data }) {
state.profile = data;
state.dataloaded = true;
},
}
Now in my vue js file
export default{
data: () => ({
profile_form:{
nickname:'',
first_name:'',
last_name:'',
email:''
}
}),
computed:{
...mapGetters({
user: 'profileDetails',
}),
},
methods:{
setUpDetails(){
this.profile_form.email = this.user.email; //the value is always undefined
}
},
mounted(){
this.$store.dispatch('getProfileDetails').then(
(res)=>{
console.log(res); //this is undefined
this.setUpDetails(); ///this is never executed
}
);
this.setUpDetails(); //tried adding it here
}
By checking with the vue developer tools i can see that the vuex has data but my component cant fetch the data in vuex after calling the dispatch in the action to fetch the data.
Where am i going wrong.
Nb: AM using the data to update a form like this
<input v-model="profile_form.email" >
Your mounted method expects a return (res) from getProfileDetails, but the action isn't returning anything, so you could simply try
const actions = {
getProfileDetails ({ commit }) {
return axios.get('/my-profile-details')
.then((response) => {
let data = response.data;
commit(types.RECEIVED_USERS, {data});
return data // put value into promise
},
);
}
}
However, it's more usual to commit to store from within the action (which you are doing) and let the component get the new values from a getter (which you have) - i.e one-way-data-flow.
This is how I'd set it up.
data: () => ({
profile_form:{
nickname:'',
first_name:'',
last_name:'',
email:''
}
}),
mounted(){
this.$store.dispatch('getProfileDetails')
}
computed: {
...mapGetters({
user: 'profileDetails',
}),
}
watch: {
user (profileData){
this.profile_form = Object.assign({}, profileData);
}
},
methods:{
submit(){
this.$store.commit('submituser', this.profile_form)
}
},

Categories