One data from two get method - reactjs

I have two separate axios get method which map response data to separate data object. Then I map the data in render. I want to put data from both axios in to one object to map only one object in render. How could i do that?
One of two get function
getData() {
axios
.get("http://localhost/GetAll?", {
params: { rok: this.state.rok, idUchwaly: "1" },
headers: { Authorization: "Bearer " + this.state.token }
})
.then(response =>
response.data.map(data2 => ({
IDA: `${data2.idZadania}`,
idWersji: `${data2.idWersji}`,
Dzial: `${data2.dzial}`
}))
)
.then(data2 => {
if (data2 == "") {
} else {
this.setState({ data2, isLoadingdane: true });
}
})
.catch(error => this.setState({ error }));
}
Then I map data into a table
{this.state.isLoadingdane ? (
data2.map(user2 => {
const { IDA, idWersji, DziaƂ } = user2;
return (
<tr id={IDA}>
<td>
<p>{idWersji}</p>
</td>
<td>
<p>{Dzial}</p>
</td>
</tr>
);
})
) : (
<tr>
<td colSpan="3">
<center>
<p>Brak</p>
</center>
</td>
</tr>
)}
I want one table in which i could put values from both get function
something like this: {value from getData}{value from getData2}

Instead of putting the response to the axios request in state directly, you could return the promise and wait for both of the requests to finish with Promise.all and then merge the objects in both arrays into one array.
Example
class App extends React.Component {
componentDidMount() {
Promise.all([this.getData(), this.getData2]).then(([data1, data2]) => {
this.setState({
data2: data1.map((item, index) => ({ ...item, ...data2[index] })),
isLoadingdane: true
});
});
}
getData = () => {
return axios
.get("http://localhost/GetAll?", {
params: { rok: this.state.rok, idUchwaly: "1" },
headers: { Authorization: "Bearer " + this.state.token }
})
.then(response =>
response.data.map(data2 => ({
IDA: `${data2.idZadania}`,
idWersji: `${data2.idWersji}`,
Dzial: `${data2.dzial}`
}))
);
};
getData2 = () => {
return axios.get(/* ... */);
// ...
};
render() {
// ...
}
}

Bartek, you need to map results like that:
const first = [{
x: 'x',
y: 'y',
}];
const second = [{
x: 'x',
z: 'z',
}];
const all = first.map(o => ({ ...o, ...second.find(f => f.x === o.x)}));
console.log(all);

Related

prevent api from being called before state is updated

I have a list of objects. I want to make an api call once the location field of the object is changed. So for that, I have a useEffect that has id, index and location as its dependencies. I have set a null check for the location, if the location isn't empty, I want to make the api call. But the thing is, the api is being called even when the location is empty, and I end up getting a 400. How can I fix this and make the call once location isn't empty?
const [plants, setPlants] = useState([
{
name: 'Plant 1',
id: uuidv4(),
location: '',
coords: {},
country: '',
isOffshore: false,
}
]);
const [locationIDObject, setlocationIDObject] = useState({
id: plants[0].id,
index: 0
});
const handlePlantLocChange = (id, index, value) => {
setPlants(
plants.map(plant =>
plant.id === id
? {...plant, location: value}
: plant
)
)
setlocationIDObject({
id: id,
index: index
})
}
const getCoords = (id, index) => {
axios.get('http://localhost:3002/api/coords', {
params: {
locAddress: plants[index].location
}
}).then((response) => {
if(response.status === 200) {
handlePlantInfoChange(id, PlantInfo.COORD, response.data)
}
})
}
const handler = useCallback(debounce(getCoords, 5000), []);
useDeepCompareEffect(() => {
if(plants[locationIDObject.index].location !== '')
handler(locationIDObject.id, locationIDObject.index);
}, [ locationIDObject, plants[locationIDObject.index].location])
return (
<div className='plant-inps-wrapper'>
{
plants.map((item, idx) => {
return (
<div key={item.id} className="org-input-wrapper">
<input placeholder={`${item.isOffshore ? 'Offshore' : 'Plant ' + (idx+1) + ' location'}`} onChange={(e) => handlePlantLocChange(item.id, idx, e.target.value)} value={item.isOffshore ? 'Offshore' : item.location} className="org-input smaller-input"/>
</div>
)
})
}
</div>
)
I think your useCallback is not updating when value of your variables is changing and that is the issue:
Although the check is correct, but the call is made for older values of the variable. You should update the dependencies of your useCallback:
console.log(plants) inside getCoords might help you investigate.
Try this:
const handler = useCallback(debounce(getCoords, 5000), [plants]);
So it turns out the issue was with my debouncing function. I don't know what exactly the issue was, but everything worked as expected when I replaced the debouncing function with this:
useEffect(() => {
console.log("it changing")
const delayDebounceFn = setTimeout(() => {
getCoords(locationIDObject.id, locationIDObject.index)
}, 4000)
return () => clearTimeout(delayDebounceFn)
},[...plants.map(item => item.location), locationIDObject.id, locationIDObject.index])

return value from object function inside a map

I'm trying to run a getUserName function that is being called inside an Observable pipe, map, then another map. I can return a single value but I can't seem to map the passed array to then filter out item.name if it matches the id passed in. If I show the code maybe it will be easier to understand:
Not working:
export const fetchDesignsData = (usersArray: [Users]) => (dispatch: Dispatch<Action>) => {
console.log(usersArray);
const DESIGNS_URL = `http://localhost:5000/designs`;
dispatch({
type: "FETCH_DATA_REQUEST",
});
const responsePromise = axios.get(DESIGNS_URL);
const response$ = from(responsePromise);
response$
.pipe(
map((response) => {
const newArray: { name: string; courses: number; wales: number; last_updated: string; by: any }[] = [];
response.data.map((item: { name: any; courses: any; wales: any; updated: any; user_id_last_update: any }) => {
return newArray.push({
name: item.name,
courses: item.courses,
wales: item.wales,
last_updated: item.updated,
by: getUserName(item.user_id_last_update, usersArray),
});
});
dispatch({
type: "FETCH_DATA_SUCCESS",
payload: newArray,
});
})
)
.subscribe();
};
const getUserName = (userNumber: number, usersArray: [Users]) => {
return () => {
usersArray.forEach((item) => {
if (item.id === userNumber) {
return item.name;
}
});
};
};
Basically usersArray looks like this:
[{id: 1, name: "Walter Doe"},
{id: 2, name: "John Doe"}]
so I need to map that array then see if the item.id === userNumber, if yes, return item.name. But it just returns blank every time. Probably because its inside an Observable
You need to use filter as there you need to return array which satisfy condition.
//...
const getUserName = (userNumber: number, usersArray: [Users]) => {
return () => {
usersArray.filter((item) => item.id === userNumber)
.map(item => item.name)
});
};
};
//...
This worked in the end, but it doesn't show the item.name value in my component on page load, only if I route away and come back, something to do with my useEffect and dispatch.
const getUserName = (userNumber: number, usersArray: [Users]) => {
return usersArray.filter((item) => item.id === userNumber).map((item) => item.name);
};

Render Array in Vuejs

I tried to render a list of items by Vuejs, the code below is a simplified version of it. Basically, I need it to display data, the state and data appears in VueDevTool but not on the page.
<template>
<div>
<h1>{{this.sendersList.length}}</h1> <!-- 0 -->
<h1>{{senders.length}}</h1> <!-- 0 -->
</div>
</template>
<script>
export default{
data () {
return {
sendersList: []
}
},
created () {
this.$store.dispatch('getAllSenders', {
app_id: this.$route.params.chat_id
}).then(response => {
this.sendersList = response
})
},
computed: {
senders(){
return this.$store.getters.getAllSenders
}
}
}
</script>
Store code returns data as normal, VueDevtool can see it but I cant find away to render it on the front-end
getAllMessages(context, data){
return new Promise((resolve, reject) => {
axios.post('messages/getAllMessages', {
sender_id: data.sender_id
}).then(response => {
let payload = []
for (let index = 0; index < response.data.length; index++) {
payload.push({
message_id: response.data[index].message_id,
message_content: response.data[index].message_content,
message_type: response.data[index].message_type,
message_sentiment: response.data[index].message_sentiment,
sender_id: response.data[index].sender_id,
user_id: response.data[index].user_id,
from_sender: response.data[index].from_sender,
created_date: response.data[index].created_date,
})
}
context.commit('getAllMessages', payload)
resolve(payload)
}).catch(error => {
reject(error)
})
})
},
Try change this
<h1>{{this.sendersList.length}}</h1>
To this
<h1>{{sendersList.length}}</h1>

Load date by request fetch()

I have got a JSON file and I want to call it by fetch() request. My JSON looks like this:
{
id: { hotelId: "102835", provider: { provider_id: "23", dmnid: 3984 } },
hotelinfo: {
name: "Pera Rose Hotel",
hotelsearch: {
realname: "Pera Rose Hotel",
hotelid: 0.0,
hotelimage: "",
webserviceimage:
"http://service.stage.Paximum.com/media/images/product/2/1/2/2/102835-fed561d75dec40ca4d83fd6fc9da9967-jpg/pera_rose_hotel.jpg",
countryid: 1002247,
ecountryname: "Turkey",
ecityname: "Istanbul",
cityid: 1177676,
star: 4,
desc:
"This hotel is located in the Istanbul's business, shopping and entertainment centre, around a 5-minute walk from the historical Galata Tower, the world's second oldest subway and some 8 minutes' walk away from Taksim Square. In Taksim itself, around 5 minutes' walk from the hotel, guests will find restaurants, bars, shops and clubs. The nearest underground station is Taksim-Meydan, a 10-minute walk away and guests will find the Hagia Sophia, the Topkapi Palace, the Grand Bazaar and the Egyptian Market all around a 15-minute ride away by public transport, as is Sirkeci Station. Istanbul Airport is around 15 km away.",
enable: "",
delete: ""
},
information: { viewname: "-" }
}
}
But my setState function is not executing and there is this error:
SyntaxError: "JSON.parse: expected ',' or '}' after property value in
object at line 1 column 549 of the JSON data"
And it is because of fieldd desc. As you can see there are some words in desc such as Istanbul's which have '. Is there any way to solve this problem?
(When I use ajax() request to load json.bc file there is no error.)
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
library: null,
perPage: 20,
currentPage: 1,
maxPage: null,
filter: ""
};
}
componentDidMount() {
fetch("/json.bc", {
method: "POST",
body: "cityid=[##cms.form.cityid##]"
})
.then(response => response.text())
.then(text => {
var Maindata = JSON.parse(text.replace(/\'/g, '"'));
this.setState(
state => ({
...state,
data: Maindata
}),
() => {
this.reorganiseLibrary();
}
);
})
.catch(error => console.error(error));
}
reorganiseLibrary = () => {
const { filter, perPage, data } = this.state;
let library = data;
if (filter !== "") {
// ...
}
library = _.chunk(library, perPage);
this.setState({
library,
currentPage: 1,
maxPage: library.length === 0 ? 1 : library.length
});
};
previousPage = event => {
this.setState({
currentPage: this.state.currentPage - 1
});
};
nextPage = event => {
this.setState({
currentPage: this.state.currentPage + 1
});
};
handlePerPage = evt =>
this.setState(
{
perPage: evt.target.value
},
() => this.reorganiseLibrary()
);
renderLibrary = () => {
const { library, currentPage } = this.state;
if (!library || (library && library.length === 0)) {
return <div class="nodata">No Result</div>;
}
return library[currentPage - 1]
.sort((a, b) => a.total - b.total)
.map((item, i) => <div class="item">{item.id}</div>);
};
render() {
const { library, currentPage, perPage, maxPage } = this.state;
return (
<div className="Main-wrapper">
<div className="wrapper-data">{this.renderLibrary()}</div>
<ul id="page-numbers">
<li class="nexprev">
{currentPage !== 1 && (
<button onClick={this.previousPage}>
<span class="fa-backward" />
</button>
)}
</li>
<li class="controls active">{this.state.currentPage}</li>
<li class="controls">{this.state.maxPage}</li>
<li class="nexprev">
{currentPage < maxPage && (
<button onClick={this.nextPage}>
<span class="fa-forward" />
</button>
)}
</li>
</ul>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("Result"));
Replace the single quotes inside double quotes string with ' html entity, then replace single quotes with double quotes and lastly (optional) replace single quotes html entity with single quotes.
function stringToJSON(str) {
// convert single qoute inside double qoutes to html entity
const singleQuoteToEntity = str.replace(/"[^"]+"/g, function(m) {
return m.replace(/\'/g, ''');
});
const replaceSingleQuotes = singleQuoteToEntity.replace(/\'/g, '"');
return replaceSingleQuotes.replace(/'/g, '\'');
}
const jsonString = "{ 'id': { 'hotelId': '102835', 'provider': { 'provider_id': '23', 'dmnid': 3984 } }, 'hotelinfo': { 'name': 'Pera Rose Hotel', 'hotelsearch': { 'realname': 'Pera Rose Hotel', 'hotelid': 0.0, 'hotelimage': '', 'webserviceimagine': 'http://service.stage.Paximum.com/media/images/product/2/1/2/2/102835-fed561d75dec40ca4d83fd6fc9da9967-jpg/pera_rose_hotel.jpg', 'countryid': 1002247, 'ecountryname': 'Turkey', 'ecityname': 'Istanbul', 'cityid': 1177676, 'star': 4, 'desc': \"This hotel is located in the Istanbul's business, shopping and entertainment centre, around a 5-minute walk from the historical Galata Tower, the world's second oldest subway and some 8 minutes' walk away from Taksim Square. In Taksim itself, around 5 minutes' walk from the hotel, guests will find restaurants, bars, shops and clubs. The nearest underground station is Taksim-Meydan, a 10-minute walk away and guests will find the Hagia Sophia, the Topkapi Palace, the Grand Bazaar and the Egyptian Market all around a 15-minute ride away by public transport, as is Sirkeci Station. Istanbul Airport is around 15 km away.\", 'enable': '', 'delete': '' }, 'information': { 'viewname': '-' } } }";
console.log(JSON.parse(stringToJSON(jsonString)))
In your App component you do the following
class App extends React.Component {
....
stringToJSON = (str) => {
// convert single qoute inside double qoutes to html entity
const singleQuoteToEntity = str.replace(/"[^"]+"/g, function(m) {
return m.replace(/\'/g, ''');
});
const replaceSingleQuotes = singleQuoteToEntity.replace(/\'/g, '"');
return replaceSingleQuotes.replace(/'/g, '\'');
}
componentDidMount() {
fetch("/json.bc", {
method: "POST",
body: "cityid=[##cms.form.cityid##]"
})
.then(response => response.text())
.then(text => {
var Maindata = JSON.parse(this.stringToJSON(text));
this.setState(
state => ({
...state,
data: Maindata
}),
() => {
this.reorganiseLibrary();
}
);
})
.catch(error => console.error(error));
}
....

React-redux: Nested array is being duplicated

I'm trying to create an order table (array) that has a nested "products" array in each order.
The order table is rendering as expected, but the products are the same for every order.
OrderTable Component (simplified for clarity)
class OrderTable extends Component {
componentWillMount() {
this.props.fetchPtOrders(this.props.patient_id);
}
renderOrders(orders) {
return orders.map((order) => {
return (
<tr key={order.id}>
<td>
<ProductTable id={order.id}/>
</td>
</tr>
);
});
}
render() {
const { orders, loading, error } = this.props.orderTable;
return (
<div class="container divcon">
<h1>Orders</h1>
<table class="pto">
<tbody>
{this.renderOrders(orders)}
</tbody>
</table>
</div>
);
}
}
export default OrderTable;
<ProductTable id={orders.id}/> arrays the products and is basically a copy of the above (minus the ProductTable component).
I tried debugging using IDs (3000022 and 3000023) and found that everything is being done in batches.
3000022 contains products / 3000023 is empty.
The response from the requests is being used for both IDs, and is overwritten with every iteration. Only the last response is used for every order.
ProductTable Container:
function mapStateToProps(state, ownProps) {
return {
ProductTable: state.order_products.ProductTable,
order_id: ownProps.id
};
}
const mapDispatchToProps = (dispatch) => {
return {
fetchPtOrderProducts: (id) => {
dispatch(fetchPtOrderProducts(id)).then((response) => {
!response.error ? dispatch(fetchOrderProductsSuccess(response.payload.data)) : dispatch(fetchOrderProductsFailure(response.payload.data));
});
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ProductTable);
Product Fetch action:
export function fetchPtOrderProducts(id) {
const request = axios({
method: 'get',
url: `${ROOT_URL}/order_product/search.php?s=${id}`,
headers: []
});
return {
type: FETCH_PTORDER_PRODUCTS,
payload: request
};
}
Product Success action:
export function fetchOrderProductsSuccess(order_products) {
console.log("products fetched")
return {
type: FETCH_ORDER_PRODUCTS_SUCCESS,
payload: order_products
};
}
Product Reducers
case FETCH_ORDER_PRODUCTS:// start fetching products and set loading = true
return { ...state, ProductTable: {order_products:[], error: null, loading: true} };
case FETCH_ORDER_PRODUCTS_SUCCESS:// return list of products and make loading = false
return { ...state, ProductTable: {order_products: action.payload, error:null, loading: false} };
How can I make orders.map() and <ProductTable /> array one ID at a time?
Thanks for you help! Sorry if anything is unclear... I'm a complete newbie.
As far as I can see you are overriding the same field in your state.
You should change ProductTable field to maintain order_id for each product list. It should be a map of order_id to order_products.
Note that my code might contain mistakes because I have no runnable example to edit.
Something like this:
ProductTable Container:
function mapStateToProps(state, ownProps) {
return {
orderProductTable: state.order_products.ProductTable[ownProps.id],
order_id: ownProps.id
};
}
const mapDispatchToProps = (dispatch) => {
return {
fetchPtOrderProducts: (id) => {
// Add `id` argument to fetchOrderProductsSuccess here
dispatch(fetchPtOrderProducts(id)).then((response) => {
!response.error ? dispatch(fetchOrderProductsSuccess(id, response.payload.data)) : dispatch(fetchOrderProductsFailure(response.payload.data));
});
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(OrderProductTable);
Product Fetch action:
export function fetchPtOrderProducts(id) {
const request = axios({
method: 'get',
url: `${ROOT_URL}/order_product/search.php?s=${id}`,
headers: []
});
return {
type: FETCH_PTORDER_PRODUCTS,
payload: {id}
};
}
Product Success action:
export function fetchOrderProductsSuccess(id, order_products) {
console.log("products fetched")
// Add `id` field here
return {
type: FETCH_ORDER_PRODUCTS_SUCCESS,
payload: {id, products: order_products}
};
}
Product Reducers
case FETCH_ORDER_PRODUCTS:// start fetching products and set loading = true
return { ...state, ProductTable: {...(state.ProductTable || {}), [action.payload.id]: {order_products:[], error: null, loading: true}}};
case FETCH_ORDER_PRODUCTS_SUCCESS:// return list of products and make loading = false
return { ...state, ProductTable: {...(state.ProductTable || {}), [action.payload.id]: {order_products: action.payload.products, error:null, loading: false}}}};

Resources