Reactjs: How to save to var the result obtained from .then - javascript

How can I save the data obtained from .then
Example:
import React, { Component, Fragment } from "react";
//Función que conecta un componente a Redux store.
import { connect } from "react-redux";
class PruebasAPI extends Component {
state = {
Obtenerdata: [],
};
GetPriceCurrencie = () => {
const CoinbasePro = require('coinbase-pro');
const publicClient = new CoinbasePro.PublicClient();
//publicClient.getProductTicker(sobre).then(response=> alert(response.price))
publicClient.getProductTicker('ETH-EUR').then(output => {
this.setState({
Obtenerdata: output
});
}
)
console.log("test123:", this.Obtenerdata )
return this.Obtenerdata;
};
componentDidMount() {
this.GetPriceCurrencie();
}
componentWillReceiveProps(newProps) {
if (newProps.token) {
this.GetPriceCurrencie();
}
}
render() {
console.log("Value is:", this.Obtenerdata )
return (
<Fragment>
TEST 1
<br></br>
<div>
<br></br>
Test result: {this.Obtenerdata}
</div>
</Fragment>
);
}
}
const mapStateToProps = state => {
return {
token: state.token
};
};
export default connect(mapStateToProps)(PruebasAPI);
The error seen on console.log("test123:", this.Obtenerdata ) is undefined.
If i uncoment the line:
//publicClient.getProductTicker(sobre).then(response=> alert(response.price))
I have the number obtained: xxx.xx
How to save the response to a var ?
Thank you.

state = {
Obtenerdata: [],
};
Obtenerdata is in your component's state object
So you need to do this.state.Obtenerdata instead of this.Obtenerdata

you can storage in a state using .then(response => this.setState({ Obtenerdata: response}); anda get data using this.state.Obtenerdata

Related

Why I'm getting maximum update depth exceeded error when setting data to context (React)

In my React project I wanted to share the currency, which selected by the user, within the components using a context. Context functionality works fine, however, there is a small issue that I want to fix. It is setting default currency to the context. So, when the web is started at the very beginning there will be a default currency set to the context, which is going to come from the selection that is provided from the endpoint. I used an if-statement as shown in CurrencySelector.js but I was getting that error "Maximum Update Depth Exceeded." I provided my code for the context and currency selection component.
import React, { Component, createContext } from "react";
const CurrencyContext = createContext();
class CurrencyContextProvider extends Component {
state = { selectedCurrency: "uuu" };
setCurrency = (c) => {
this.setState({ selectedCurrency: c });
};
render() {
return (
<CurrencyContext.Provider
value={{ ...this.state, setCurrency: this.setCurrency }}
>
{this.props.children}
</CurrencyContext.Provider>
);
}
}
class CurrencySelector extends React.Component {
constructor(props) {
super(props);
console.log("CurrencySelector constructor");
this.state = { currencies: [] };
}
async componentDidMount() {
let currencies = (await this.getCurrencies()).data
.currencies;
this.setState({ currencies: currencies });
}
async getCurrencies() {
return await fetchAnyQuery(`query{ currencies }`);
}
render() {
return (
<CurrencyContext.Consumer>
{(currencyContext) => {
const {
selectedCurrency,
setCurrency,
} = currencyContext;
return (
<select
name="currency-selector"
onChange={(event) => {
setCurrency(event.target.value);
}}
>
{this.state.currencies.map((currency, index) => {
//When I wrote this if-statement I got the error
if (index == 0) {
setCurrency(currency);
}
return (
<option value={currency}>{currency}</option>
);
})}
</select>
);
}}
</CurrencyContext.Consumer>
);
}
}
//When I wrote this if-statement I got the error
if (index == 0) {
setCurrency(currency);
}
Yes – you would get an error, since you're mutating state during render, which is expressly forbidden. (This isn't specific to using a context.)
You have a couple options I can think of:
move the currency loading to the context provider, and have the context provider set the default currency once it's loaded the currencies
"fake" having a default currency set if one hasn't been set (but that will get hairy really quickly)
Here's an example of the first option.
See how getCurrencies() has been hoisted up to the componentDidMount() of the provider.
A bit of extra care will need to be applied, since it might be that the currencies haven't been loaded yet; see how we only render "Loading..." for that time.
import React, { Component, createContext } from "react";
const CurrencyContext = createContext();
// Fake fetcher function that just takes a bit of time.
function fetchAnyQuery() {
return new Promise((resolve) =>
setTimeout(() => resolve({ data: { currencies: ["a", "b", "c"] } }), 1000)
);
}
class CurrencyContextProvider extends Component {
state = { selectedCurrency: "uuu", currencies: undefined };
setCurrency = (c) => {
this.setState({ selectedCurrency: c });
};
async componentDidMount() {
const currencies = (await this.getCurrencies()).data.currencies;
this.setState(({ selectedCurrency }) => {
if (!currencies.includes(selectedCurrency)) {
// If the selected currency is invalid, reset it to the first one
selectedCurrency = currencies[0];
}
return { currencies, selectedCurrency };
});
}
async getCurrencies() {
return await fetchAnyQuery(`query{ currencies }`);
}
render() {
return (
<CurrencyContext.Provider
value={{ ...this.state, setCurrency: this.setCurrency }}
>
{this.state.currencies ? this.props.children : <>Loading...</>}
</CurrencyContext.Provider>
);
}
}
class CurrencySelector extends React.Component {
render() {
return (
<CurrencyContext.Consumer>
{(currencyContext) => {
const { selectedCurrency, currencies, setCurrency } = currencyContext;
return (
<div>
<select
name="currency-selector"
value={selectedCurrency}
onChange={(event) => {
setCurrency(event.target.value);
}}
>
{currencies.map((currency) => (
<option value={currency} key={currency}>
{currency}
</option>
))}
</select>
<br />
Selected: {selectedCurrency}
</div>
);
}}
</CurrencyContext.Consumer>
);
}
}
export default function App() {
return (
<CurrencyContextProvider>
<CurrencySelector />
</CurrencyContextProvider>
);
}

Saving state to localStorage [duplicate]

I have no idea How to store the react js state into localstorage.
import React, { Component } from 'react'
import './App.css';
import { auth,createUserProfileDocument } from './firebase/firebase.utils'
import { TodoForm } from './components/TodoForm/TodoForm.component'
import {TodoList} from './components/TodoList/TodoList.component'
import {Footer} from './components/footer/footer.component'
import Header from '../src/components/header/header.component'
import {Redirect} from 'react-router-dom'
import {connect} from 'react-redux'
import {setCurrentUser} from './redux/user/user.actions'
export class App extends Component {
constructor(props) {
super(props)
this.input=React.createRef()
this.state = {
todos:[
{id:0, content:'Welcome Sir!',isCompleted:null},
]
}
}
todoDelete = (id) =>{
const todos = this.state.todos.filter(todo => {
return todo.id !== id
})
this.setState({
todos
})
}
toDoComplete = (id,isCompleted) =>{
console.log(isCompleted)
var todos = [...this.state.todos];
var index = todos.findIndex(obj => obj.id === id);
todos[index].isCompleted = !isCompleted;
this.setState({todos});
console.log(isCompleted)
}
addTODO = (todo) =>{
todo.id = Math.random()
todo.isCompleted = true
let todos = [...this.state.todos, todo]
this.setState({
todos
})
}
unsubscribeFromAuth = null;
componentDidMount() {
const { setCurrentUser } = this.props;
this.unsubscribeFromAuth = auth.onAuthStateChanged(async userAuth => {
if (userAuth) {
const userRef = await createUserProfileDocument(userAuth);
userRef.onSnapshot(snapShot => {
setCurrentUser({
id: snapShot.id,
...snapShot.data()
});
});
}
setCurrentUser(userAuth);
});
}
componentWillUnmount() {
this.unsubscribeFromAuth();
}
render() {
return (
<div className='App'>
<Header />
<TodoForm addTODO={this.addTODO} />
<TodoList
todos={this.state.todos}
todoDelete={ this.todoDelete}
toDoComplete={ this.toDoComplete}
/>
<Footer/>
</div>
)
}
}
const mapStateToProps = ({ user }) => ({
currentUser: user.currentUser
});
const mapDispatchToProps = dispatch => ({
setCurrentUser: user => dispatch(setCurrentUser(user))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
in my input Form
import './TodoForm.style.css'
export class TodoForm extends Component {
constructor(props) {
super(props)
this.state = {
content : ''
}
}
handleChange = (e) =>{
this.setState({
content: e.target.value
})
}
handleSubmit =(e) =>{
e.preventDefault();
this.props.addTODO(this.state);
this.setState({
content: ''
})
}
render() {
return (
<div className='inputTask'>
<form onSubmit={ this.handleSubmit}>
<input
className="textBox"
type='text'
onChange={ this.handleChange}
value={this.state.content}
placeholder='what you want to do ...'
/>
</form>
</div>
)
}
}
export default TodoForm
I have no idea How to store the react js state into localstorage.
i searched on internet but unable to find the exact solution all the codes that i think is necessary post.
You can use reactLocalStorage to save any data in local storage
import {reactLocalStorage} from 'reactjs-localstorage';
reactLocalStorage.set('var', true);
reactLocalStorage.get('var', true);
reactLocalStorage.setObject('var', {'test': 'test'});
reactLocalStorage.getObject('var');
reactLocalStorage.remove('var');
reactLocalStorage.clear();
Read out the localStorage item in the componentDidMount callback. Simply read the item you want to get, check if it exists and parse it to a usable object, array or datatype that need. Then set the state with the results gotten from the storage.
And to store it, simply handle it in an event handler or helper method to update both the state and the localStorage item.
class ExampleComponent extends Component {
constructor() {
super();
this.state = {
something: {
foo: 'bar'
}
}
}
componentDidMount() {
const storedState = localStorage.getItem('state');
if (storedState !== null) {
const parsedState = JSON.parse(storedState);
this.setState({ something: parsedState });
}
}
clickHandler = (event) => {
const value = event.target.value;
const stringifiedValue = JSON.stringify(value);
localStorage.setItem('state', stringifiedValue);
this.setState({ something: value });
}
render() {
return (
<button onClick={clickHandler} value={this.state.something}>Click me</button>
);
}
}
Set data in localStorage
key-value pair :
localStorage.setItem('key_name',"value");
object
localStorage.setItem('key_name', JSON.stringify(object));
Remove data from localStorage
localStorage.removeItem('key_name');
Get data from localStorage
let data = localStorage.getItem('key_name');
object :
let data = JSON.parse(localStorage.getItem('key_name'));
clear localStorage (delete all data)
localStorage.clear();

State is being initialized with [object Object] in setState

In the async function below, I call stationData just to confirm that I'm passing an array of objects into bartData (which is just an empty array). Attached is a response of the array of Objects that I am receiving. However, when trying to use this.state.bartData (to confirm that it does have the array of objects), my return function is returning bartData as undefined. Any ideas?
import React from 'react';
const bartKey = process.env.REACT_API_BART_API_KEY;
class StationBaseRoutes extends React.Component{
constructor(props){
super(props);
this.state = {
isLoading: true,
station: [],
stationAbbv: 'ALL',
destination: '',
bartData: []
}
}
componentDidMount(){
this.getAllStationRoutes();
}
async getAllStationRoutes(){
try{
setInterval(async () => {
const response = await fetch(`http://api.bart.gov/api/etd.aspx?cmd=etd&orig=${this.state.stationAbbv}&key=${bartKey}&json=y`);
const jsonResponse = await response.json();
const apiData = jsonResponse.root;
const stationData = apiData.station;
console.log(stationData);
this.setState(({
isLoading: false,
bartData: stationData
}), () => {
console.log(`Callback: ${this.state.bartData}`)
})
}, 20000)
} catch(error){
console.log(error);
}
}
getRoutes = () => {
console.log(`bartData: ${this.bartData}`)
}
render(){
const {station, destination} = this.state;
return(
<div>
<h2>Calling get routes: {this.getRoutes()}</h2>
<h2>Origin: {station}</h2>
<h3>Destination: {destination}</h3>
</div>
)
}
}
export default StationBaseRoutes;
Responses: https://imgur.com/gallery/Luk9MCX
There's a couple of bugs here.
First of all, getRoutes() is using this.bartData instead of this.state.bartData
Secondly, all your objects in console.log are being converted to strings. You can change it to
console.log('bartData:', this.state.bartData);
to be able to see the actual data.
I was unable to get the Bart API to work in a codesandbox, so I had to mock the API... however, the data is still structured the same.
On that note, the API is working as expected, you just need to map over the objects in the this.state.bartData array and deconstruct the properties you want to show.
Working example: https://codesandbox.io/s/031pn7w680
import map from "lodash/map";
import React, { Component, Fragment } from "react";
import { fakeAPI } from "../../api/fakeAPI";
class StationBaseRoutes extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
station: [],
stationAbbv: "ALL",
destination: "",
bartData: []
};
this.getAllStationRoutes = this.getAllStationRoutes.bind(this);
}
componentDidMount() {
this.getAllStationRoutes();
}
async getAllStationRoutes() {
try {
const res = await fakeAPI.get();
const apiData = res.data.root;
const stationData = apiData.station;
this.setState({
isLoading: false,
bartData: stationData
});
} catch (error) {
console.log(error);
}
}
render() {
const { bartData, isLoading } = this.state;
return (
<div className="app-container">
{isLoading ? (
<p className="t-a-c">Loading...</p>
) : (
<Fragment>
<h1 className="t-a-c">Bart Stations</h1>
{map(bartData, ({ name, etd }) => (
<div className="jumbotron station" key={name}>
<h1>Origin: {name}</h1>
{map(etd, ({ destination }) => (
<li key={destination}>Destination: {destination}</li>
))}
</div>
))}
<pre className="preview">
<code>{JSON.stringify(bartData, null, 4)}</code>
</pre>
</Fragment>
)}
</div>
);
}
}
export default StationBaseRoutes;

React/Redux firing action->render before update a store

A have a simply react/redux app. I Fetch data from API async but component not waiting for data and firing render.
class RestaurantList extends React.Component {
componentWillMount() {
this.props.getRestaurantList();
}
render() {
console.log("render");
let {translation} = store.getState().app;
//------------I NEED DATA ON THIS LET (restaurantList)
let {restaurantList} = this.props.restaurants;
return (
<div>
<TableContainer data={restaurantList}/>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
restaurants: state.restaurants
};
};
const mapDispatchToProps = (dispatch) => {
return {
getRestaurantList() {
dispatch(ACTIONS.getRestaurantList());
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(RestaurantList);
On my action i fetching data using axios :
export function getRestaurantList() {
console.log("action");
return dispatch => {
axios({
method: "GET",
url: URLS.BASE_URL + URLS.URL_RESTAURANT_LIST
}).then((response) => {
console.log(response);
dispatch({
type: CONST.GET_RESTAURANT_LIST,
payload: response.data
})
})
}
}
And my component fired method ComponenWillMount after that render () and next store which update store and set good data to my variable. Maybe u give me advice how to do that to have on my render my fetching data because now on my table I transfer undefined on start. Maybe you give me an example to using another framework like redux-saga or other.
You could try conditionally rendering your TableContainer component so the table will only be rendered once there is data available:
renderTable() {
let { restaurantList } = this.props.restaurants
if (restaurantList) {
return <TableContainer data={ restaurantList } />
} else {
return <div></div>
}
}
render() {
return (
<div>
{ this.renderTable() }
</div>
)
}

Wait for react-promise to resolve before render

So I have a large set of data that I'm retrieving from an API. I believe the problem is that my component is calling the renderMarkers function before the data is received from the promise.
So I am wondering how I can wait for the promise to resolve the data completely before calling my renderMarkers function?
class Map extends Component {
componentDidMount() {
console.log(this.props)
new google.maps.Map(this.refs.map, {
zoom: 12,
center: {
lat: this.props.route.lat,
lng: this.props.route.lng
}
})
}
componentWillMount() {
this.props.fetchWells()
}
renderMarkers() {
return this.props.wells.map((wells) => {
console.log(wells)
})
}
render() {
return (
<div id="map" ref="map">
{this.renderMarkers()}
</div>
)
}
}
function mapStateToProps(state) {
return { wells: state.wells.all };
}
export default connect(mapStateToProps, { fetchWells })(Map);
You could do something like this to show a Loader until all the info is fetched:
class Map extends Component {
constructor () {
super()
this.state = { wells: [] }
}
componentDidMount() {
this.props.fetchWells()
.then(res => this.setState({ wells: res.wells }) )
}
render () {
const { wells } = this.state
return wells.length ? this.renderWells() : (
<span>Loading wells...</span>
)
}
}
for functional components with hooks:
function App() {
const [nodes, setNodes] = useState({});
const [isLoading, setLoading] = useState(true);
useEffect(() => {
getAllNodes();
}, []);
const getAllNodes = () => {
axios.get("http://localhost:5001/").then((response) => {
setNodes(response.data);
setLoading(false);
});
};
if (isLoading) {
return <div className="App">Loading...</div>;
}
return (
<>
<Container allNodes={nodes} />
</>
);
}
Calling the render function before the API call is finished is fine. The wells is an empty array (initial state), you simply render nothing. And after receiving the data from API, your component will automatically re-render because the update of props (redux store). So I don't see the problem.
If you really want to prevent it from rendering before receiving API data, just check that in your render function, for example:
if (this.props.wells.length === 0) {
return null
}
return (
<div id="map" ref="map">
{this.renderMarkers()}
</div>
)
So I have the similar problem, with react and found out solution on my own. by using Async/Await calling react
Code snippet is below please try this.
import Loader from 'react-loader-spinner'
constructor(props){
super(props);
this.state = {loading : true}
}
getdata = async (data) => {
return await data;
}
getprops = async (data) =>{
if (await this.getdata(data)){
this.setState({loading: false})
}
}
render() {
var { userInfo , userData} = this.props;
if(this.state.loading == true){
this.getprops(this.props.userData);
}
else{
//perform action after getting value in props
}
return (
<div>
{
this.state.loading ?
<Loader
type="Puff"
color="#00BFFF"
height={100}
width={100}
/>
:
<MyCustomComponent/> // place your react component here
}
</div>
)
}

Categories