select tag with hashes.map function - reactjs

I have a question about the getHashes(), there is a map-function that I want to list the hashes in a tag. The listItems is not defined... why?
Can I get some help with this?
import React, { Component } from 'react';
import axios from 'axios';
class Filter extends Component {
constructor(props) {
super(props);
this.state = {
hash: [
"aSj1T", "CD6oL"
]
}
}
getHashes(){
const hashes = this.state.hash;
const listItems = hashes.map((hashes) => <option>{hashes}</option>);
for (var i = 0; i < hashes.length; i++){
const hashUrl = "https://api/v1/hashes/" + hashes[i];
axios.get(hashUrl)
.then((response) => {
const data = response.data[0];
this.state.hash.push(data.hash);
})
.catch((error) => {
console.log(error);
});
}
}
render() {
return (
<div>
<select name="select"
type="select" value={this.getHashes}>
{listItems}
</select>
</div>
);
}
export default Filter;
I stripped down the code, it is with reux axios and much more on my text editor. But i hope you can run this in your text editor to help. It is not tested. If you just explain it is also cool.

1- this.state.hash.push(data.hash); is not a good idea you are mutating the state not changing it by setState
2- listItems is defined inside the function getHashes but never been added to the state or the component instance so you don't have access to it inside the render function
It is not obvious what you are trying to achieve by setting the value of select to a function

Related

I can't get my API data to render with the map function React.js

The API does not render and it says this.state.weather.map is not a function. I need help, I have tried different ways of mapping through but does not change the outcome. Any feedback?
import React from 'react';
import axios from 'axios';
export default class Weather extends React.Component {
constructor(props) {
super(props)
this.state = {
weather: []
}
}
async componentDidMount(){
axios.get("http://api.weatherapi.com/v1/current.json?key=?=nyc").then(res => {
console.log(res);
this.setState ({weather: res.data})
});
}
renderWeather(){
this.state.weather.map(weather => {
return (
<p>{weather.location.name}</p>
)
})
}
render () {
return (
<div>
{this.renderWeather()}
</div>
)
}
}
renderWeather(){
return this.state.weather.map(weather => {
return(
<p>{weather.location.name}</p>
)
})
}
you have missed the return statement inside the renderWeather function, above snippet works for you
The API returns JSON.
this.setState ({weather: res.data})
Check the typeof res.data. Is is probably not an array but an object, hence this.state.weather.map is not a function, because Array.map() is an array method.
Make sure that you set the state properly to an array and it should work just fine..

ReactJS - setState() is not updating

I have a single page create-react-app project and the issue I am having is that the state is not updating. I have cut some of my code out just to make the example a bit shorter and easier to follow. The function where setState() is called is in form_change().
My goal here is to change the color of the text when there is an error, but even {this.state.test} isn't updating. I have tried putting console.log()s in various locations to get around the async nature of setState, but unfortunately they seem to show that state is never updated. It has been a while since I have used React, so there is a chance I am doing something very silly!
Thanks in advance for your help.
Here is my code:
import React,{Component} from 'react';
import './App.css';
import Dropdown from 'react-dropdown'
import classes from './classes.module.css'
import firebase from 'firebase';
import 'react-dropdown/style.css';
const axios = require('axios');
class App extends Component {
render(){
const error_empty = (param)=>{
if (this.state.error===undefined){
return false
}
else{
if (this.state.errors.find(el => el === param) === undefined){
return false
}
else return true
}
}
const form_change = (event, param)=>{
let form={...this.state.form};
form[param]=event.target.value;
let errors =verified(form);
console.log(form); //as expected
console.log(errors); //as expected
//works up til here. setState not updating for some reason.
this.setState({form:form,errors:errors,test:'Hello World'})
}
const verified = (data)=>{
let errors = [];
let form = data;
errors.push('ean')
return errors}
this.state = {
example:['abc'],
form:{
example:"abc"
}
}
return (
<div className="App">
<header className="App-header">
<div className={classes.button_holder}>
<div className={classes.page_button} onClick={()=>{null}}>
{this.state.test}
</div>
</div>
<div className={classes.user_form}>User Update Form
<div>
<input className={classes.input_text} style={{color: error_empty()?'red':'black'}} value={this.state.form.ean} onChange={(event)=>{form_change(event,'ean')}} placeholder={"EAN"}></input>
</div>
</div>
</header>
</div>
);
}
}
export default App;
Move initialization of state outside render function this.state.
Initialise your state in constructor
Don't update your state (this.setState) in render because this will lead to infinitive loop.
Move your functions error_empty(), form_change() and verified() outside the render.
To call function onChange use this
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
example:['abc'],
form:{
example:"abc"
}
error: ""
}
}
error_empty = (param) => {
if(this.state.error===undefined) {
return false
}
else {
if(this.state.errors.find(el => el === param) === undefined) {
return false
}
return true
}
}
...
render() {
...
<input ... onChange={(event) => {this.form_change(event,'ean')}}/>
...
}
}

Rendering loop error with react axios setState

I have different ingredients(vodka, gin, whiskey...) json files in a dummy folder.
I have an IngredientList.js where I select one ingredient and pass it down to
IngredientSearch.js
The IngredientSearch.js gets the relevant json file based on the ingredient name and then I set the state of ingredientRes to the res.data.drinks
Problem I am getting is that when I print the console.log(newVals) --> the console logs the arrays from the json infinitely. Seems like I am rerendering something infinitely.
What is wrong with my setup?
IngredientSearch.js:
import React, { Component } from 'react';
import axios from 'axios';
class IngredientSearch extends Component {
constructor() {
super();
this.state = {
ingredientRes: []
};
}
componentDidUpdate(prevProps) {
let ingredient = this.props.ingredient; //for example: vodka
this.getIngredient_drinks(ingredient);
}
getIngredient_drinks = (ingredient) => {
if(ingredient !== null) {
axios.get(`../dummy/${ingredient}.json`)
.then((res)=>{
let newVals = [];
newVals.push(res.data.drinks);
//console.log(newVals); // keeps relogging the arrays
this.setState({ ingredientRes: newVals });
}).catch((err)=>{
console.log(err);
})
}
}
render() {
return (
<div>
IngredientSearch Results
I want to map the ingredientRes here
</div>
)
}
}
export default IngredientSearch;
You may call setState() immediately in componentDidUpdate() but note that it must be wrapped in a condition like -
if (this.props.ingredient !== prevProps.ingredient) {
this.getIngredient_drinks(ingredient);
}
Otherwise it will cause an infinite loop.
For reference - https://reactjs.org/docs/react-component.html#componentdidupdate

getting Objects are not valid as a React child error

I'm trying to make a fetch request to my server and set the response json as the component's state.
I get this error
Objects are not valid as a React child (found: object with keys {description,
id, matched_substrings, place_id, reference, structured_formatting, terms, types}). If you meant to render a collection of children, use an array instead.
in li (at Search.js:25)
in ul (at Search.js:30)
in div (at Search.js:28)
in Search (at index.js:8)
this is my code -
import React from 'react'
import { ReactDOM } from "react-dom";
export default class Search extends React.Component {
constructor(props) {
super(props);
this.state = {
places: []
}
this.handleUserInput = this.handleUserInput.bind(this)
}
handleUserInput(e) {
var searchInput = e.target.value;
var url = '/searchLocation/autocomplete?text=' + (searchInput)
if (searchInput.length > 2) {
fetch(url).then(function(response) {return response.json()})
.then((responseJson) => this.setState({places: responseJson["predictions"]}));
//.then( responseJson => console.log(responseJson["predictions"]))
}
}
render() {
const placeList = this.state.places.map(place =>
{
return <li>{place}</li>
});
return (
<div>
<input onChange={this.handleUserInput} type="text" id="PlaceSearch" />
<ul>
{ placeList }
</ul>
</div>
);
}
}
I found similiar errors by googling it but none helped..
Thank you very much for helping
This issue is you are trying to render place which I assume is an object inside the li.
you need to choose which property to render
ex:
return <li>{place.id}</li>
I think you're missing parenthesis;
const placeList = this.state.places.map(place =>
{
return ( <li>{place}</li> )
});

React filtering the state without ruining it

Im trying to make a search function that renders the name of the people that is matched in a search text input.
The problem is that I set the state to the items that match the search, and then the initial state is lost so no more searching can be done since the state will be empty. So how do I "fill up" the state each time?
Or maybe there is some other way without actually setting the state that im not aware of.
I tried to fix this with an attempt to reset to initial state when the handleSearch function is called right before the filter but that doesnt work.
import React from 'react';
import Header from './Header';
import peopleData from '../persons.json';
class App extends React.Component {
constructor(){
super();
this.handleSearch = this.handleSearch.bind(this);
this.state = {
people: peopleData
}
}
handleSearch(wordToMatch){
this.setState({ people: peopleData }); //Attempt to reset to initial state
const result = this.state.people.filter(d => {
const regex = new RegExp(wordToMatch, 'gi');
return d.Name.match(regex);
});
this.setState({ people: result })
}
render() {
const list = this.state.people.map((d, i) => <li key={i}>{d.Name}</li>);
return (
<div className="myApp">
<Header
tagline={"testing"}
handleSearch={this.handleSearch}
/>
<ul className="contentBody">
{list}
</ul>
</div>
)
}
}
export default App;
Component with the search input:
import React from 'react';
class Header extends React.Component {
render() {
return (
<header>
<input
type="text"
placeholder={this.props.tagline}
ref={(input) => this.searchInput = input}
onChange={() => this.props.handleSearch(this.searchInput.value)}
>
</input>
</header>
)
}
}
export default Header;
How my data looks like
[
{
"Name": "Adam",
"Born": 1971
},
{
"Name": "Bob",
"Born": 1999
},
etc etc for 20 more names
The setState function won't immediately update the state object. So when you reference this.state.people, it will reference the state prior to the setState call. You can update your code to:
handleSearch(wordToMatch) {
const result = peopleData.filter(d => {
const regex = new RegExp(wordToMatch, 'gi');
return d.Name.match(regex);
});
this.setState({
people: result
})
}
In the handleSearch set the state for the searchString variable. Then in the render method, instead of simply mapping the state, you first filter the people list, and that result is what you map.
Change:
const list = this.state.people.map((d, i) => <li key={i}>{d.Name}</li>);
into this:
const list = this.state.people.filter(d => {
const regex = new RegExp(this.state.searchString, 'gi');
return d.Name.match(regex);
}).map((d, i) => <li key={i}>{d.Name}</li>);
This way, the list in the state is left unaltered, and you filter when rendering.

Resources