I want to populate dropdowns only if the a certain condition is met.
I am using the axios get method for fetching data.
The code is as follows -
componentDidMount = e => {
axios
.get("https://jsonplaceholder.typicode.com/users")
.then(function (res) {
let FullData = res.data;
});
};
My form is as follows-
<form>
<select>address</select>
<option id={FullData.zipcode}>{FullData.street}</option>
</form>
I need this to work only if the { FullData.city } is "Gwenborough".
Please refer here for the JSON.
Here's a way to do it. You generally need to put your values in state, so whenever they are received in asynchronous way, the component gets updated.
Here's a Demo sandbox
class DropDown extends React.Component {
constructor(props) {
super(props);
this.state = {
FullData: [],
}
}
componentDidMount=(e)=>{
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => res.json())
.then(res => {
this.setState({
FullData: res
})
})
}
render() {
let { FullData } = this.state;
return (
<form>
<label>Address </label>
<select>
{FullData
.filter(user => user.address.city === "Gwenborough")
.map(user => {
return <option key={user.id} id={user.zipcode}>{user.address.street}</option>
})}
</select>
</form>
);
}
}
Note I was using fetch instead of axios.
Another note - I really like Dexter's answer and the way the action is put into separate function. It looks like a better approach to structuring your code in general. It probably wouldn't work as it is only because of how your data is structured: you get and array of users and you only have city and street inside the address key. Cheers!
Something like this can help. Note your question isn't clear enough to provide working examples to help me understand the full scope of what you're talking about, so this is my best guess on the solution to your question.
constructor(){
this.selection=null;
this.doSomeTesting=this.doSomeTesting.bind(this);
}
doSomeTesting(FullData){
if(FullData.city === "Gwenborough"){
return (<option id={FullData.zipcode}>{FullData.street}</option>);
}
return ""; //return nothing useful if not what you're looking for
}
componentDidMount=(e)=>{
axios.get('https://jsonplaceholder.typicode.com/users')
.then(function(res){
let FullData=res.data
this.selection = this.doSomeTesting(FullData);
})
}
render(){
<form>
<select>address</select>
{this.selection}
</form>
}
Related
I want to store unique key and value in my class component state(selectedFeatures) as a list of key-value pairs, by taking the arguments which are passed from the body. ex: {“user1”:"opt1", “user2”:"opt3"}. The key must be unique, which means if the same key received from the body value should be updated to the relevant key which is stored previously
I did it in this way and it gives an error as “this.state.selectedFeatures is not iterable”. Therefore how to resolve this.
import React, { Component} from 'react';
import {features} from '../../services';
class UserData extends Component {
constructor(props) {
super(props)
this.state = {
featureTypes:[],
selectedFeatures:{}
}
}
getSelectedFeatures =(event,keyValue)=>{
const features = {};
features[keyValue] = event.target.value
this.setState({selectedFeatures: features})
}
componentDidMount(){
//http request from service component
features().then(response => {
this.setState({featureTypes:response})
})
.catch(error => {
console.log(error)
})
}
render() {
const {featureTypes} = this.state
return (
<div>
{featureTypes.map((feature, i) => (
<div key={i}>
<label>
<h4>
{feature.feature}
</h4>
</label>
<select
defaultValue="select-feature"
onChange={(event) => this.getSelectedFeatures(event, feature.feature)}>
{feature.types.map((type, i) => (
<option key={i} value={type}>
{type}
</option>
))}
</select>
</div>
))}
</div>
)
}
}
export default UserData
Without creating an array just simply adding to an object can be achieved via this method
addTo = (event, val) => {
this.setState((prev) => ({
selectedFeatures: {
...prev.selectedFeatures,
[event.target.value]: val
}
}));
};
NOTE I changed the name from getSelectedFeatures to addTo from simplicity + because get would mean it returns something. In this case, you send and add it.
the prev is a previews state that was before the state change.
Also I went a step further and created a demo project https://codesandbox.io/s/flamboyant-lake-4rvfz?file=/src/App.js
Inside of it there are multiple different containers that you may click and it will save what has been click as a event.target and a value they themself send to the method. If the container is clicked again OR a different but same type container is clicked, the value is overriten rather then added as a new parameter. Its constructed using class, as in your code. This is a simple quick demo that, after analizing, you may adapt to it as you wish with any code you want.
I'm trying to create a search bar that will load a list of user's names from an api when input is added to the search bar and im getting an error. im not quite sure what to make the parameters of the .filter method. or if im even using the correct method. I thought about using lodash _.filter but not sure how or where to implement that. im new to react so keep that in mind! id be very thankful for any suggestions
import React, { Component } from "react";
import ReactDOM from "react-dom";
import './App.css'
class App extends Component {
constructor() {
super();
this.state = {
people: [],
search: ''
};
}
componentDidMount() {
fetch("https://randomuser.me/api/?page=3&results=10&seed=abc")
.then(results => results.json())
.then(data => this.setState({ people: data.results }));
}
updateSearch(event) {
this.setState({ search: event.target.value })
}
render() {
let filteredPeople = this.state.people.filter(
(people) => {
return people.data.results.indexOf(e.target.value) !== -1;
//or maybe use .includes
}
);
return (
<div className="card">
<div className="firstlast">
{filteredPeople.map(people => (
<div id="names">{people.name.first} {people.name.last}</div>
))}
</div>
<input type="text" value={this.state.search} onChange={this.updateSearch.bind(this)} />
</div>
);
}
}
export default App;
error message:
Error in /~/App.js (43:32)
Cannot read property 'results' of undefined
When you type in input, you need to use that value to filter your data,
{ this.state.search !=="" ? this.state.people.filter( people => people.name.first.includes(this.state.search)).map( (people,index) => (
<p key={index}>{people.name.first} {people.name.last}</p>
))
:
this.state.people.map((people,index) => (
<p key={index}>{people.name.first} {people.name.last}</p>
))
}
Demo
Note: I have used key={index} because I didn't find anything unique in your response, but always try to avoid using index as key.
You need to access people.results instead of people.data.results
Cause this.setState({ people: data.results }) adds data.results to people directly.
I was wondering what is the best way to display data from a rest api.
Actually what I do:
Call fetch function from componentDidMount();
setState to store my response
Check with ternary when render() if the value is set or not
it look like this :
(getcall() is a fetch function) :
async componentDidMount() {
const response= await getCall(
`event?ref=23876186`, // this is just to illustrate
);
this.setState({ payload: response})
}
Then in render() I do some :
{this.state.payload ? (
<h1>{this.state.payload.event.name}</h1>) : ( <h1></h1>)}
I though about calling my fetch function from the constructor, but it's weird to call an async function in a constructor, you loose the aync purpose.
I imagine some case like for an input :
<Input
type="text"
name="name"
id="name"
**value={this.state.event.name}**
placeholder="Name..."
onChange={this.handleName}
required
/>
If I want to set a value for it, like this.state.event.name, if I have 10 fields, I will have 10*2 times this kind of code because for each one I wrote a ternary.
So what is the best way to display data from an api call ?
Thanks for your answers
Instead of adding a lot of ternaries where you check if payload is set, you can return null early from the render method if it is not set yet.
Example
class App extends React.Component {
state = {
payload: null
};
async componentDidMount() {
const response = await getCall("/event?ref=23876186");
this.setState({ payload: response });
}
render() {
const { payload } = this.state;
if (payload === null) {
return null;
}
return <div>{/* ... */}</div>;
}
}
I am using reactjs select 2 but I don't know how to make it work so that when a user types something in a ajax request is made and the results are sent back.
I see it has some async options but I don't get how it works and how I would get it to work with axios.
I come up with this but it is kinda laggy when a user types(probably because it is re-rendering it after each type) and when the user selects a choice the value disappears.
export default class TestComponent extends Component {
constructor(props) {
super(props);
this.state = {value: ""};
}
onInputChange(option) {
this.getOptionsAsync(option)
}
getOptionsAsync(newInput) {
var that = this;
console.log("ffd", newInput)
axios.get(`https://localhost:44343/api/States/GetStatesByText?text=${newInput}`)
.then(function (response) {
var formatedResults = response.data.map((x)=> {
return {value: x.id, label: x.name}
})
that.setState({
options: formatedResults,
value: newInput
})
})
.catch(function (error) {
});
}
render() {
console.log(this.state.value, "value")
return (
<div className="test">
<Select
onInputChange={this.onInputChange.bind(this)}
value={this.state.value}
options={this.state.options }
/>
</div>
);
}
}
You're going to be doing an api call every single time that you type a letter with the current way you're doing things. I would recommend just loading the states once at the beginning, perhaps in your ComponentDidMount() method.
If you pass the isSearchable prop to React-Select it will automatically work as a filter anyways.
Another thing I've had to do in this case which I believe will fix your change problem is to make sure it calls the handler on change not just on input change.
Pass this prop:
<Select
value={this.state.value}
options={this.state.options }
onChange={value => {
if (value) this.onInputChange(value)
else this.onInputChange('')
}
/>
Due to the way this is automatically bound to arrow functions, you won't have to bind to this if you change your onInputChange to the following:
onInputChange = (value) => {
this.getOptionsAsync(value)
}
Finally, you should be setting the state in the above function so the value is stored.
onInputChange = (value) => {
this.getOptionsAsync(value)
this.setState({value})
}
Is it possible to return a function inside the .then callback?
I want to do something like this:
axios.post('url_api/endpoint')
.then(function(response){
renderAdmissionReponse(){
<div>Success response.data</div>
}
})
To later render it in a component like this: "
<div className="row spacer">
{this.renderAdmissionReponse()}
</div>
Is it possible to do it?
I can actually understand your need, however, your above code is wrong!
What you want is: after data are loaded successfully by using axios, the data will be rendered properly on page. If so, you can use the following way:
constructor(props) {
// ...
this.state = ({
admissionResponse: [],
// your other state variables here
})
}
renderAdmissionReponse = (data) => {
this.setState({
admissionResponse: data,
});
}
// ... You can put this inside `ComponentDidMount()`, then just call the function to setState with returned data
axios.post('url_api/endpoint')
.then((response) => {
this.renderAdmissionReponse(response.data);
})
// ...
render() {
return (
<div className="row spacer">
<div>{this.state.admissionResponse.authorizationId}</div>
<div>{this.state.admissionResponse.authorizationNum}</div>
{this.state.admissionResponse.lineItems.map((line) =>{
return(
<div>{line.id}</div>
<div>{line.lineItemNumber}</div>
)
})}
</div>
);
}
Please also check your response.data structure then retrieve the correct keys, the above code I just try to explain about correct react's way on how to load data asynchronously and render on page after that. Please post here some errors if any, thanks.