react setState function is not workin - reactjs

I am new at react and
I have been trying to apply event handling in react but facing some Problem on onclick event.
When the button "show me of germany" is called the Page then stuck to loading only ...
Here is the code i have written ..
class App extends Component {
constructor(props) {
super(props);
this.state = { articles: [],
isLoaded:false ,
country:'us'
}
this.change = this.change.bind(this);
}
componentDidMount() {
const APIurl = `https://newsapi.org/v2/top-headlines?country=${this.state.country}&apiKey=${API_KEY}`;
fetch(APIurl)
.then(response => response.json())
.then(json => {
this.setState({
articles: json.articles,
isLoaded:true
})
})
}
// function to change the state
change()
{
this.setState({
articles: [],
isLoaded:false ,
country:"de"
})
}
render() {
const { isLoaded,articles } = this.state;
if(!isLoaded)
{
return (<h1>Loading....</h1>)
}
return (
<div>
<Navbar/>
<button onClick={this.change}>show me of germany</button>
<ul>
{articles.map(item=>(
<News item={item}/>
))}
</ul>
</div>
);
}
}
export default App;
Hope you understood the problem

You have to do request again.
class App extends Component {
constructor(props) {
super(props);
this.state = {
articles: [],
isLoaded: false,
country:'us'
}
this.change = this.change.bind(this);
}
componentDidMount() {
fetchData(this.state.country);
}
componentDidUpdate(prevProps, prevState) {
const { country: prevCountry } = prevState;
const { country: nextCountry } = this.state;
if (prevCountry !== nextCountry) {
fetchData(nextCountry);
}
}
change() {
this.setState({ country: 'de' });
}
fetchData(country) {
this.setState({ articles: [], isLoaded: false });
fetch(
`https://newsapi.org/v2/top-headlines?country=${country}&apiKey=${API_KEY}`
)
.then(res => res.json())
.then(({ articles }) => {
this.setState({ articles, isLoaded: true });
})
.catch(console.error);
}
render() {
//...
}
}
export default App;

Related

fetch data from mongoDB, setstate and pass props to child component is not working

beneath is my code
class Root extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
}
}
componentDidMount() {
this.getDataFromDb();
}
getDataFromDb = () => {
fetch('http://localhost:3001/getData')
.then((data) => data.json())
.then((res) => {
if(res !== this.state.data) {
this.setState({ data: res}, () => console.log(this.state.data));
}
});
};
render() {
return(
<div>
<IRPage data={this.state.data}></IRPage>
</div>
)
}
}
class IRPage extends Component {
print = () => {
console.log(this.props.data);
}
render() {
return (
<div className="container m-5">
<button onClick={this.print}></button>
</div>
)
}
}
callback function of setstate in getDatafromDB in Root component work successfully,
but when it pass to child component IRPage, and click print button, result is undefined.
Thank you for helping
You code seems to work as you intended it.
I tried to replicate what you wrote and it's working. checkout this jsfiddle
class Root extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
}
}
componentDidMount() {
this.getDataFromDb();
}
getDataFromDb = () => {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then((data) => data.json())
.then((res) => {
if(res !== this.state.data) {
this.setState({ data: res}, () => console.log(this.state.data));
}
});
};
render() {
return(
<div>
<IRPage data={this.state.data}></IRPage>
</div>
)
}
}
// here I have added React to import Components from, because I don't know what import statement is
class IRPage extends React.Component {
print = () => {
console.log(this.props.data);
}
render() {
return (
<div className="container m-5">
<button onClick={this.print}></button>
</div>
)
}
}
ReactDOM.render(<Root />, document.querySelector("#app"))

this.state is giving null after api call

I am consoling state right after my function call in componentDidMount but it's giving data as EMPTY String.
import React, { Component } from "react";
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: ""
};
}
getData = () => {
functionApiCall().then(res => {
this.setState({
data: res.data
}); // Here the state is getting set
})
}
componentDidMount() {
this.getData();
console.log(this.state.data); //Empty string
}
render() {
return <></>;
}
}
export default App;
Any help will be appreciated.Thank you
Well, I think the api call is returning null , maybe change it like this
getData = () => {
functionApiCall().then(res => {
if(res && res.data) {
this.setState({
data: res.data
})// Here the state is getting set
}
}
}
Above should be fine, but just in case try this
getData = () => {
return new Promise(function(resolve, reject) {
functionApiCall().then(res => {
if(res && res.data) {
this.setState({
data: res.data
}, () => { resolve(res.data) })// Here the state is getting set
}
} });
}
And componentDidMount wait for your promise which resolves after state is set
async componentDidMount(){
await this.getData();
console.log(this.state.data) //NULL
}
setState is asynchronous so you cannot immediately access it.
You can render conditionally like this:
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: null
};
}
getData = () => {
functionApiCall().then(res => {
this.setState({
data: res.data
});
});
};
componentDidMount() {
this.getData();
}
render() {
if (!this.state.data) {
return <div>Loading...</div>;
} else {
return <div>Data: {JSON.stringify(this.state.data)}</div>;
}
}
}
export default App;
Sample codesandbox with a fake api

onClick doesn't work while trying to render: reactjs, basic API fetch

I'm trying to do a basic API fetch and show that information onClick using a button called GENERATE. All it should do for now is show the first url in the json I receive.
Once that is achieved, I want it to show the next url on each click.
App.js
import React, { Component } from 'react';
import { ThemeProvider, createToolkitTheme } from 'internaltools/theme';
import { AppHeader } from 'internaltools/app-header';
const LIGHT_THEME = createToolkitTheme('light');
const DARK_THEME = createToolkitTheme('dark');
const API = 'https://hn.algolia.com/api/v1/search?query=';
const DEFAULT_QUERY = 'redux';
class App extends Component {
constructor(props) {
super(props);
this.state = {
hits: [],
isLoading: false,
error: null,
};
}
componentDidMount(){
this.setState({ isLoading: true });
fetch(API + DEFAULT_QUERY)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong with the API...');
}
})
.then(data => this.setState({ hits: data.hits[0], isLoading: false }))
.catch(error => this.setState({ error, isLoading: false }));
}
render() {
const { hits, isLoading, error } = this.state;
return (
<>
<button onClick={hits.url}>GENERATE</button>
</>
);
}
}
Please help me find out why my button doesn't work. And how do I iterate over the urls on each click, i.e. show the next url from the json on each click. Thanks.
You should pass a function name to your onClick handler. Then in that function you can access the data you wanted.
enter code here
import React, { Component } from 'react';
import { ThemeProvider, createToolkitTheme } from 'internaltools/theme';
import { AppHeader } from 'internaltools/app-header';
const LIGHT_THEME = createToolkitTheme('light');
const DARK_THEME = createToolkitTheme('dark');
const API = 'https://hn.algolia.com/api/v1/search?query=';
const DEFAULT_QUERY = 'redux';
class App extends Component {
constructor(props) {
super(props);
this.state = {
hits: [],
isLoading: false,
error: null,
hitsCount: 0
};
this.handleClick = this.handleClick.bind(this);
}
componentDidMount(){
this.setState({ isLoading: true });
fetch(API + DEFAULT_QUERY)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong with the API...');
}
})
.then(data =>
this.setState({ hits: data.hits, hitsCount: 0 ,isLoading: false
}))
.catch(error => this.setState({ error, isLoading: false }));
}
handleClick(){
this.setState(prevState => ({ hitsCount: prevState.hitsCount + 1
}));
}
render() {
const { hits, hitsCount, isLoading, error } = this.state;
return (
<>
<div>
count: {hitsCount}
url: {hits[hitsCount].url}
</div>
<button onClick={this.handleClick}>GENERATE</button>
</>
);
}
}
You need to pass an onClick handler function to update a state value.
Here's a codesandbox that stores the hits array in state along with a current index, and a handler that simply increments the index.
Consider This:
Read through the comments in the code to get the updates.
class App extends Component {
constructor(props) {
super(props);
this.state = {
hits: [],
currentHit: 0, //add a state currentHit to hold the url that is displayed by now
isLoading: false,
error: null,
};
}
componentDidMount(){
this.setState({ isLoading: true });
fetch(API + DEFAULT_QUERY)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong with the API...');
}
})
.then(data => this.setState({ hits: data.hits, isLoading: false })) //Make hits array holding all the hits in the response instead of only the first one
.catch(error => this.setState({ error, isLoading: false }));
}
handleClick = () => {
this.setState(prevState => ({
currentHit: prevState.currentHit + 1,
}));
}
render() {
const { hits, isLoading, error, currentHit } = this.state;
// pass the handleClick function as a callback for onClick event in the button.
return (
<>
<p>{hits[currentHit].url}<p/>
<button onClick={this.handleClick.bind(this)}>GENERATE</button>
</>
);
}
}
Here is the working code, on each click next url will be shown.
codesandbox link
handleChange method can work if you want to append the url from array as well. Or you could just increment the index in this function.
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
state = {
data: [],
index: 0
};
componentDidMount() {
this.setState({ isLoading: true });
fetch("https://reqres.in/api/users")
.then(response => {
if (response) {
return response.json();
} else {
throw new Error("Something went wrong with the API...");
}
})
.then(data => this.setState({ data: data.data }))
.catch(error => this.setState({ error }));
}
handleChange = () => {
let i =
this.state.index < this.state.data.length ? (this.state.index += 1) : 0;
this.setState({ index: i });
};
render() {
return (
<div className="App">
<span>
{this.state.data.length && this.state.data[this.state.index].avatar}
</span>
<button onClick={this.handleChange}>GENERATE</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

How do I use enter to submit the Semantic React Search

I'm trying to set up my search so when I click enter it will begin to search and redirect to the search page. I was looking through the documentation and it wasn't clear how to set this up. How can I set up pressing enter to begin the search? I'm having a tough time figuring this out, even though I think it should be simple.
class SearchBar extends Component {
constructor(props) {
super(props)
this.state = {query: '', results: [], isLoading: false}
}
componentWillMount() {
this.resetComponent()
}
resetComponent = () => this.setState({ isLoading: false, results: [], value: '' })
search(query) {
this.setState({ query });
axios
.get(`/api/search?query=${query}`)
.then(response => {
console.log(query);
this.setState({ results: response.data});
})
.catch(error => console.log(error));
}
handleSearchChange = (query) => {
this.search(query);
this.setState({ isLoading: true, query })
setTimeout(() =>
this.setState({
isLoading: false,
}) , 300)
}
handleResultSelect = (e, { result }) => this.setState({ query: result} )
render () {
const resultRenderer = ({ title }) => <List content = {title}/>
return (
<Search
loading={this.state.isLoading}
onResultSelect={this.handleResultSelect}
onSearchChange={(event) => {this.handleSearchChange(event.target.value)}}
showNoResults={false}
query={this.props.query}
selectFirstResult = {true}
resultRenderer={resultRenderer}
results ={this.state.results}
{ ...this.props} />
);
}
}
export default SearchBar
Thanks!
Here is a minimal example of how you can do this.
import React from 'react'
import { Form, Input } from 'semantic-ui-react';
class FormExampleForm extends React.Component {
constructor(props) {
super(props);
this.state = {
query: ''
}
}
handleFormSubmit = () => {
console.log('search:', this.state.query);
}
handleInputChange = (e) => {
this.setState({
query: e.target.value
});
}
render() {
return (
<Form onSubmit={this.handleFormSubmit}>
<Form.Input placeholder='Search...' value={this.state.query} onChange={this.handleInputChange} />
</Form>
)
}
}
export default FormExampleForm;
Here is a working example:https://stackblitz.com/edit/react-q5wv1c?file=Hello.js
Modify the Search component in semantic-ui react source code to implement the onKeyPress handler

Fetch not working in React.js

I am trying to fetch the message outputted by the following endpoint:
http://helloworld-env-2.5fwknpgms8.us-east-2.elasticbeanstalk.com/
I just ran a create-react-app to create my application and changed the code in the App.js file
New Code:
import React, { Component } from 'react';
import './App.css';
class App extends React.Component {
constructor(props){
super(props);
this.state = {
error: null,
isLoaded: false,
items: ""
};
}
componentDidMount(){
console.log("mounting component");
fetch("http://helloworld-env-2.5fwknpgms8.us-east-2.elasticbeanstalk.com/")
.then((result) => {
this.setState({
isLoaded: true,
items: result
});
});
}
render() {
console.log("rendering");
const isLoaded = this.state.isLoaded;
if(isLoaded){
return (<div> {this.state.items} </div>);
}
else{
return (
<div>loading</div>
);
}
}
}
export default App;
I keep getting the loading message.
You need to parse the response from fetch:
componentDidMount(){
fetch("http://helloworld-env-2.5fwknpgms8.us-east-2.elasticbeanstalk.com/")
.then((result) => result.json()) // here
.then((result) => {
const { a } = result; // access 'a' key from response
this.setState({
isLoaded: true,
items: a
});
});
}
Here are the docs.

Resources