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

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>
)
}

Related

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

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

React: Async function not being called

Why is my aync call fetchButtonTeams() below not being called. I am trying to print its results in console.log(this.state.data) below. Even if i call it in the render() I get infinite loops or errors. Can anyone suggest what to do?
I just want to print the results in console.log in render()
class TeamFilter extends Component {
constructor() {
super();
this.state = { data: [] };
}
async fetchButtonTeams() {
const response = await fetch(`/api/teams`);
const json = await response.json();
console.log(json)
this.setState({ data: json });
}
handleTeamSelection = e => {
this.props.setTeam(e.target.title);
this.props.fetchTeams(e.target.title)
};
render() {
let test = ['Chaos', 'High Elves', 'Orcs']
this.fetchButtonTeams()
console.log(this.state.data)
return (
<DropdownButton id="dropdown-team-button" title={this.props.team_name}>
{test.map(cls => (
<div key={cls}>
<Dropdown.Item onClick={this.handleTeamSelection} title={cls}>{cls}</Dropdown.Item>
</div>
))}
</DropdownButton>
)
}
}
const mapStateToProps = state => {
return {
team_name: state.team_name
}
};
const mapDispatchToProps = dispatch => {
return {
fetchCards: path => dispatch(fetchCards(path)),
fetchTeams: params => dispatch(fetchTeams(params)),
setTeam: team_name => dispatch({ type: "SET_TEAM", team_name })
}
};
export default connect(mapStateToProps, mapDispatchToProps)(TeamFilter)
The reason you get infinite loops when you call the function on the render method is because each time the function is calling setState which in turn runs the function again and again, triggering an infinite loop.
I don't see where you are calling fetchButtonTeams() anywhere in your component, but a good idea for fetching data is putting the method inside a componentDidMount lifecycle method and console log inside the render method.You can learn more about lifecycle hooks here.
For your code:
class TeamFilter extends Component {
constructor() {
super();
this.state = { data: [] };
}
componentDidMount() {
this.fetchButtonTeams();
}
async fetchButtonTeams() {
const response = await fetch(`/api/teams`);
const json = await response.json();
console.log(json);
this.setState({ data: json });
}
handleTeamSelection = e => {
this.props.setTeam(e.target.title);
this.props.fetchTeams(e.target.title);
};
render() {
let test = ["Chaos", "High Elves", "Orcs"];
console.log(this.state.data);
return (
<DropdownButton id="dropdown-team-button" title={this.props.team_name}>
{test.map(cls => (
<div key={cls}>
<Dropdown.Item onClick={this.handleTeamSelection} title={cls}>
{cls}
</Dropdown.Item>
</div>
))}
</DropdownButton>
);
}
}
const mapStateToProps = state => {
return {
team_name: state.team_name
};
};
const mapDispatchToProps = dispatch => {
return {
fetchCards: path => dispatch(fetchCards(path)),
fetchTeams: params => dispatch(fetchTeams(params)),
setTeam: team_name => dispatch({ type: "SET_TEAM", team_name })
};
};
export default connect(mapStateToProps, mapDispatchToProps)(TeamFilter);

How to getById in redux

I am newbie in react and redux, trying to fetch data using api, but trying to fetch by id, unfortunately, id is undefined in redux logger and no result back from server side,
Here is my code
My route <Route path="/admin/:id" component={AdminPage} />
Action
function getAll(id){
return dispatch =>{
dispatch(request(id));
adminService.getAll(id)
.then( admin => {
dispatch(success(admin));
dispatch(alertActions.success('Welcome Back !'));
},error => {
dispatch(failure(error.toString()));
dispatch(alertActions.error(error.toString()));
});
};
function request(id) { return { type: adminConstants.GETALL_REQUEST, id } }
function success(admin) { return { type: adminConstants.GETALL_SUCCESS, admin } }
function failure(error) { return { type: adminConstants.GETALL_FAILURE, error } }
Reducer
export function admin( state={}, action){
switch(action.type){
case adminConstants.GETALL_REQUEST:
return { loading: true, id : action.id };
case adminConstants.GETALL_SUCCESS:
return { items: action.admin };
case adminConstants.GETALL_FAILURE:
return { error: action.error };
default:
return state
}
}
Service
function getAll(id){
const requestOptions = {
method : 'GET',
headers: authHeader()
};
return fetch(`${apiUrl}/admin/${id}`, requestOptions).then(handleResponse)
.then( data => { return data; });
}
AdminPage
class AdminPage extends React.Component{
componentDidMount(){
this.props.dispatch(adminActions.getAll());
}
render(){
const { admin } = this.props;
return(
<div>
<h3> Admin Panel</h3>
{admin.items &&
<ul>
{admin.items.map((data, index) =>
<li key={data.id}>
email id : {data.email},
end date : {data.dateEnd},
customerId : {data.customerId}
</li>
)}
</ul>
}
</div>
);
}
}
function mapStateToProps(state) {
const { admin } = state;
return { admin};
}
const connectedAdminPage = connect(mapStateToProps)(AdminPage);
export { connectedAdminPage as AdminPage };
Link on Home page
<Link to="/admin/5c4f69d5259f7d14434b4cb6">Admin</Link>
If you're trying to get the 'id' in
Route path="/admin/:id">
then try
console.log("mark1",this.props.match.params.id)
inside 'AdminPage' component.
If it works then you can pass it to the dispatcher via the component and use inside your function.
For more documentation try https://reacttraining.com/react-router/web/example/url-params.
If this is not what you were asking comment below and I'll edit accordingly. :)
Edit: So here is the solution for the 'AdminPage'
class AdminPage extends React.Component{
componentDidMount(){
this.props.dispatch(adminActions.getAll(this.props.match.params.id));
}
...
}
Now it should not be undefined in the action, can you confirm?

map function value not displaying

In console.log the api fetched data are displaying but in browser itis
showing only white screen. In map function have to update the state function
import React, { Component } from 'react';;
import * as algoliasearch from "algoliasearch";
class App extends React.Component {
constructor() {
super();
this.state = {
data: { hits: [] }
}
// set data to string instead of an array
}
componentDidMount() {
this.getData();
}
getData() {
var client = algoliasearch('api-id', 'apikey');
var index = client.initIndex('');
//index.search({ query:""}, function(data){ console.log(data) })
//index.search({ query:""}, function(data){ console.log("DataRecib=ved. First check this") })
index.search({
query: "",
attributesToRetrieve: ['ItemRate', 'Color'],
hitsPerPage: 50,
},
function searchDone(error, data) {
console.log(data.hits)
});
}
render() {
return (
<div id="root">
{
this.state.data.hits.map(function (data, index) {
return
<h1>{this.setState.data.ItemRate}<br />{data.Color}</h1> >
})}
</div>
);
}
}
//render(<App />, document.getElementById('app'));
export default App;
Couple of mistakes -:
You just need to use this.state.data.ItemRate instead of this.setState.data.ItemRate.
You can get state inside .map using arrow functions ( . )=> { . }
Visit https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/
render() {
return (
<div id="root" >
{
this.state.data.hits.map((data,index) => {
return<h1>{this.state.data.ItemRate}<br />{data.Color}</h1>
}
Every this.setState triggers a render() call. If you setState inside render method, you go into an infinity loop.
You want to update this.state.data.hits inside getData() function, then you can display the data like so:
this.state.data.hits.map(data =>
<h1>{data.Color}</h1>
)
For example, if console.log(data.hits) logs out the correct data, then you can:
this.setState({
data: {
hits: data.hits
}
})
EDIT:
Using the code you provided, it should be like this:'
getData = () => {
var client = algoliasearch('A5WV4Z1P6I', '9bc843cb2d00100efcf398f4890e1905');
var index = client.initIndex('dev_twinning');
//index.search({ query:""}, function(data){ console.log(data) })
// index.search({ query:""}, function(data){ console.log("Data Recib=ved. First check this") })
index.search({
query: "",
attributesToRetrieve: ['ItemRate', 'Color'],
hitsPerPage: 50,
}, searchDone = (error, data) => {
this.setState({
data: {
hits: data.hits
}
})
console.log(data.hits)
})
}

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