Consider that i have the normalized object like this in redux store
{
"entities": {
"listings_by_id": {
"1": {
"id": 1,
"address": "991 Folsom St, San Francisco, CA 94107, USA",
"info": "Triplex 4,000 sqft",
"cap": "7.1",
"position": {
"lat": 37.778519,
"lng": -122.40564
}
},
"2": {
"id": 2,
"address": "1139004, San Francisco, CA 94118, USA",
"info": "Duplex 1,500 sqft",
"cap": "6.8",
"position": {
"lat": 37.768519,
"lng": -122.43564
}
}
}
},
"result": [
1,
2
]
}
In want to display the property list in the UI. Something like
Triplex 4,000 sqf
CAP RATE: 7.1
Duplex 1,500 sqft
CAP RATE: 6.2
Do i need to denormalize again for displaying in UI? If yes, where do i handle this - mapStateToProps?
Any help would be much appreciated.
You can add result into mapStateToProps and then iterate it like this
return this.props.result.map(a=>{
return <><div>{state.entities.listings_by_id[a].info}</div><div>{state.entities.listings_by_id[a].cap}</div></>
})
Here result should be mapped like this
const mapStateToProps = (state) => ({
result:state.reducername.result
});
and state.entities is the store
import store from 'path/ReactReducers/store';
state.entities should be replaced as store.getState().reducername.
As Justcode said above, the best way is handle that on mapStateToProps function. I created a codepen to show you how to do it. https://codepen.io/aquilesb/pen/bOKrzP
//Import any modules from libraries
const { Provider, connect } = ReactRedux;
const { createStore } = Redux;
// initial state
const initialState = { test:{
"entities": {
"listings_by_id": {
"1": {
"id": 1,
"address": "991 Folsom St, San Francisco, CA 94107, USA",
"info": "Triplex 4,000 sqft",
"cap": "7.1",
"position": {
"lat": 37.778519,
"lng": -122.40564
}
},
"2": {
"id": 2,
"address": "1139004, San Francisco, CA 94118, USA",
"info": "Duplex 1,500 sqft",
"cap": "6.8",
"position": {
"lat": 37.768519,
"lng": -122.43564
}
}
}
},
"result": [
1,
2
]
}};
// create store
let store = createStore(state => state, initialState);
const ReduxTextField = ({ entities }) =>(
<ul>
{ Object.entries(entities).map((entity) =>(
<li>
<div><span style={{marginRight:'10px'}}>Info:</span>{entity[1].info}</div>
<div><span style={{marginRight:'10px'}}>CAP:</span>{entity[1].cap}</div>
</li>
))}
</ul>)
const mapStateToProps = function (state) {
return {
entities: state.test.entities.listings_by_id
}
}
//shorter way to write mapStateToProps
//const mapStateToProps = state => ({ entities: state.test.entities.listings_by_id })
const ReduxTextFieldContainer = connect(mapStateToProps, null)(ReduxTextField);
//Create teh app component which contains the button and text field
class App extends React.Component {
render() {
return (
<div>
<ReduxTextFieldContainer />
</div>
)
}
}
//Finally render to DOM!
ReactDOM.render(<Provider store={store}><App/></Provider>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/6.0.0/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.1/redux.min.js"></script>
<div id="root"></div>
Related
App.js
I am facing this issue file error - Uncaught TypeError: items.data.map is not a function. I have tried some other options but did not work. I cant seem to find what I am doing wrong.
.then((res) => res.json())
.then((json) => {
this.setState({
items: json,
DataisLoaded: true
});
})
}
render() {
const { DataisLoaded, items } = this.state;
if (!DataisLoaded) return <div>
<h1> Loading data ... </h1> </div> ;
return (
<div className = "App">
<h1> Fetch data from an api in react </h1> {
items.data.map((item) => (
<ol key = { item.data} >
Continents: {item.data[0]}
</ol>
))
}
</div>
);
}
}
export default App;
JSON Data
Nested API data from json data type.
{
"data": {
"data": [
{
"project_id": "xxxx",
"title": "xxx34",
"description": "xxx23",
"expense": 1699126,
"budget": 6418516,
"country": "xxx",
"sector": [
{
"name": "Accelerate structural transformations",
"code": "18"
}
],
"sdg": [
{
"name": "Peace, justice, and strong institutions",
"id": "16"
}
],
"signature_solution": [
{
"name": "Strengthen effective, inclusive and accountable governance",
"id": "2"
}
],
"donor": [
"Australian DFAT",
"GLOBAL FUND TO FIGHT AIDS, TUBERCULOSIS",
"UNITED NATIONS DEVELOPMENT PRO"
],
"marker": [
"Hows",
"Joint Programme",
"Partner",
"Whos",
"COVID-19 Response"
]
},
{
],
"links": {
"next": null,
"previous": null
},
"count": 44
},
"status": 200,
"success": true
}
I tried data.data.map but still facing the same error. What am I doing wrong here?
Firstly, the TypeError you got is syntax error. The implementation of an arrow function must follow by curly brackets
items.data.map((item) => (
<ol key = { item.data} >
Continents: {item.data[0]}
</ol>
))
to
items.data.map((item) => {
<ol key = { item.data} >
Continents: {item.data[0]}
</ol>
})
Secondly, items you are mapping is a nest of JSON object - key: value pair. It's not suitable for mapping.
The mapping iterator or iterating an array is perfect when used to retrieve
data from a sequence item have the same or similar structure.
E.g:
const arr = [{"id": "1", "name": "a"}, {"id": "2", "name": "b"}, {"id": "3", "name": "c"}];
arr.map((item) => {
console.log(item.id);
console.log(item.name);
})
You should pretreat your data first.
I try to interact with functions in my deployed contract using web3. It works fine to get information from metamask but it seems to return truncated value with my smart contract (?).
The request with await web3.eth.getAccounts() wotks fine, but the requests for the smart contract MyDeposit.methods.getBalance().call() and MyDeposit.methods.account().call()seem inconsistent.
here is a screen shot of html rendering
here is a screen sot of my console
I retrieve well my account (0x3B8F16325799ce799555243418df22C5c8e81f48) but I should have retrieved also 9000000000001 for MyDeposit.methods.getBalance and (0x3B8F16325799ce799555243418df22C5c8e81f48) for MyDeposit.methods.account. however, I just got (9) for MyDeposit.methods.getBalance and (0) for MyDeposit.methods.account. It looks like if only the first digit of good response was returned.
would be great if anyone could help. Txs
here is my code :
import React, { Component } from "react";
import Web3 from "web3";
import "./App.css";
import { TODO_LIST_ABI, TODO_LIST_ADDRESS, TODO_ENTER_YOUR_KEY } from "./config";
class App extends Component {
async UNSAFE_componentWillMount() {
await this.loadWeb3();
await this.loadBlockchainData();
}
async loadWeb3() {
if (window.ethereum) {
window.web3 = new Web3(window.ethereum);
await window.ethereum.enable();
} else if (window.web3) {
window.web3 = new Web3(window.web3.currentProvider);
} else {
window.alert("No ethereum broswer detected! You can check out MetaMask!");
}
}
async loadBlockchainData() {
const web3 = new Web3(
Web3.givenProvider ||
"https://goerli.infura.io/v3/" + TODO_ENTER_YOUR_KEY
);
const accounts = await web3.eth.getAccounts();
this.setState({ account: accounts[0] });
const MyDeposit = new web3.eth.Contract(TODO_LIST_ABI, TODO_LIST_ADDRESS);
console.log(MyDeposit);
const owners = await MyDeposit.methods.owner().call();
this.setState({ owner: owners[0] });
console.log("this.state.owner : " + this.state.owner);
await MyDeposit.methods.sendEther().call();
let balances = []
balances = await MyDeposit.methods.getBalance().call();
console.log(balances[0])
this.setState({ balance: balances[0] });
console.log(this.state.balance);
console.log("this.state.balance : " + this.state.balance);
}
constructor(props) {
super(props);
this.state = {
account:[],
balance: [],
owner: []
};
}
render() {
return (
<div>
<div className="container-fluid">
<div className="row">
<main
role="main"
className="col-lg-12 d-flex justify-content-center"
>
<div id="loader" className="text-center">
<p className="text-center">On progress...</p>
</div>
<div id="content">
<p> the account is : {this.state.account} </p>
<p> the balance is : {this.state.balance} </p>
<p> the owner is : {this.state.owner} </p>
<ul id="completedTaskList" className="list-unstyled"></ul>
</div>
</main>
</div>
</div>
</div>
);
}
}
export default App;
here is the config.js with smart contract ABI
export const TODO_LIST_ADDRESS = "0xe78a5c60fa13BBB677d4c1D37a007ed59bE5Ca2e";
export const TODO_ENTER_YOUR_KEY = "enter your infura key for testing";
export const TODO_LIST_ABI = [
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "getBalance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "sendEther",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address payable",
"name": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "transferEther",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
]
owner and balancese had to be declared in the array. It's now OK.
I wrote:
const owners = [await MyDeposit.methods.owner().call()];
const balances = [await MyDeposit.methods.getBalance().call()];
instead of previous:
const owners = await MyDeposit.methods.owner().call();
const balances = await MyDeposit.methods.getBalance().call();
It's now OK. I get the full field.
I have to map the nested JSON result in React. The below one is the response I got as response from backend API.
{
"id": 2,
"name": "sanjna",
"email": "vv#gmail.com",
"address": "iiiii, hhh",
"gender": "1",
"tagline": "Friendly to all",
"description": "4 years experience in programming",
"languages": "English ",
"key_skills": [
{
"id": 1,
"name": "RUBY ON RAILS, HTML, BOOTSTRAP, JQUERY, REACT",
"relevant_experience": "4"
},
{
"id": 2,
"name": "ruby",
"relevant_experience": "2"
}
],
"certifications": [
{
"id": 1,
"name": "MCA",
"institution_name": "vvv unversity",
"certification_date": "20-12-2020",
"image": null
},
{
"id": 2,
"name": "HTML training",
"institution_name": "nnn unversity",
"certification_date": "20-12-2022",
"image": null
}
],
"educations": [
{
"id": 1,
"qualification": "MCA",
"course": "Masters Degree PG",
"institute": "kkk",
"ins_location": "jjjj",
"passing_year": "2015"
}
]
}
This is my React code to get this response
const [singleUserDetail, setsingleUserDetail] = React.useState('');
let logged_user_id = job_seeker.actable_id;
const getsingleUserDetails = (logged_user_id) => {
axios
.get(`http://localhost:3001/users/${logged_user_id}`, { withCredentials: true })
.then((response) => {
const singleUserDetail = response.data;
setsingleUserDetail(response.data)
console.log(response.data); //prints the above JSON results in console
})
.catch((error) => {
console.log(" error", error);
});
};
React.useEffect(() => {
getsingleUserDetails(logged_user_id);
}, [logged_user_id]);
When I prints {singleUserDetail.name} it gives me result sanjna
{singleUserDetail.email} it gives me result vvv#gmail.com
{singleUserDetail. address} it gives me result iiiii, hhh. from my above JSON result
But how to print keyskills, certifications and educations here with mapping. I'm a beginner in React.
Youu can do something like this, my example is very simple,but you can complicate this as much as you need, with conditions or loops in loops.
<div>
{singleUserDetail.name},{singleUserDetail.email},{singleUserDetail.address},{singleUserDetail.gender},{singleUserDetail.tagline},{singleUserDetail.description}, {singleUserDetail.languages}
</div>
{singleUserDetail.key_skills.map((skill)=>{
return(
<div key={skill.id}>
{skill.name}:{skill.relevant_experience}
</div>
);
})}
{singleUserDetail.certifications.map((certification)=>{
return(
<div key={certification.id}>
{certification.name},{certification.institution_name},{certification.certification_date}
</div>
);
})}
{singleUserDetail.educations.map((education)=>{
return(
<div key={education.id}>
{education.qualification},{education.course},{education.institute}
</div>
);
})}
For more information, React documentation
Here is the app working with the one dimensional data set:
https://boiling-coast-12353.herokuapp.com/
I wrote code that made clickable buttons for each country in my data. But now I need to use a data set structured differently so I can transform the data.
My data set is now like this:
{
"2010": [
{ "Country": "Argentina", "Percentage": 10.44 },
{ "Country": "Bolivia", "Percentage": 51.62 },
...
],
"2011": [
{ "Country": "Argentina", "Percentage": 10.34 },
{ "Country": "Bolivia", "Percentage": 51.62 },
...
],
....
}
Im trying to generate a button for each country, but the code I used before no longer works:
{
this.state.data.map((data, index) => (
<button key={index}className="button-primary" onClick={() => {this.onChooseCountry(index);
}}><span className="btn-content" tabindex="-1">
</span>{data.Country}</button>
))
}
What you have actually done is changes your data from an array to JSON Object. Here is the following code on how to iterate through a nested JSON array of your structure:
class App extends React.Component{
render(){
var json = {
"2010":[{ "Country": "Argentina", "Percentage": 10.44 },
{ "Country": "Bolivia", "Percentage": 51.62 }],
"2011":[{ "Country": "Argentina", "Percentage": 10.44 },
{ "Country": "Bolivia", "Percentage": 51.62 }]
};
return <div> {Object.keys(json).map(year => json[year].map(data => <button> {year} | {data["Country"]}</button>))} </div>
}
}
ReactDOM.render(
<App/>,
document.body
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.1.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.1.1/umd/react-dom.production.min.js"></script>
The data returned from backend is as follows.
[
{
id: 1,
address: '991 Folsom St, San Francisco, CA 94107, USA',
info: 'Triplex 4,000 sqft',
cap: '7.1',
position: { lat: 37.778519, lng: -122.405640 }
},
{
id: 2,
address: '1139004, San Francisco, CA 94118, USA',
info: 'Duplex 1,500 sqft',
cap: '6.8',
position: { lat: 37.768519, lng: -122.435640 }
}
]
The reactjs code to normalize data is as follows.
import axios from '../../../util/axios';
import * as schema from '../../../schema';
import { normalize } from 'normalizr';
const normalizePropertyList = response => normalize(response.data.listings_by_id, [schema.propertyList]);
export const getPropertyList = () => axios.get('/api/v1/properties').then(normalizePropertyList);
Schema is defined as follows.
import { normalize, schema } from 'normalizr';
export const propertyList = new schema.Entity('listings_by_id', {}, { idAttribute: 'id' });
The normalized data returned is as follows.
{
"entities": {
"listings_by_id": {
"1": {
"id": 1,
"address": "991 Folsom St, San Francisco, CA 94107, USA",
"info": "Triplex 4,000 sqft",
"cap": "7.1",
"position": {
"lat": 37.778519,
"lng": -122.40564
}
},
"2": {
"id": 2,
"address": "1139004, San Francisco, CA 94118, USA",
"info": "Duplex 1,500 sqft",
"cap": "6.8",
"position": {
"lat": 37.768519,
"lng": -122.43564
}
}
}
},
"result": [
1,
2
]
}
Now in the reducer i need to access this data using selectors. I am a bit confused on how to implement this.
Any help would be appreciated.