How to change let value onClick in React - reactjs

My default value is null (let activestatus = "";), but I want it to change on click to be:
let activestatus = "?IsActive=0";
I am getting value on click (as seen in console), but the value is not passed in "let activestatus".
class App extends Component {
state = {
reservations: [],
};
componentWillMount() {
let activestatus = "";
axios
.get("https://localhost:44307/api/GetReservations/" + `${activestatus}`)
.then((response) => {
this.setState({
reservations: response.data,
});
});
}
showActive = (e) => {
e.preventDefault();
console.log(e.target.value);
this.activestatus = e.target.value;
};
render() {
let reservations = this.state.reservations.map((reservation) => {
return (
<tr>
<td>{reservation.Id}</td>
</tr>
);
});
return (
<div className="App container">
<Button
class="activity-button"
value={"?IsActive=0"}
id="active"
onClick={this.showActive}
>

Can you try to have activeStatus as part of your state? Also if you want to refresh the data from the api based on this field, then should probably use componentDidUpdate that runs on state changes.

class App extends Component {
state = {
reservations: [],
activestatus: ""
};
componentWillMount() {
axios
.get("https://localhost:44307/api/GetReservations/" + `${activestatus}`)
.then((response) => {
this.setState({
reservations: response.data,
});
});
}
showActive = (e) => {
e.preventDefault();
console.log(e.target.value);
this.setState({ activestatus: e.target.value });
};
render() {
let reservations = this.state.reservations.map((reservation) => {
return (
<tr>
<td>{reservation.Id}</td>
</tr>
);
});
return (
<div className="App container">
<Button
class="activity-button"
value={"?IsActive=0"}
id="active"
onClick={this.showActive}
>`

Thanks guys, both were helpful.
Solution:
class App extends Component {
state = {
reservations: [],
activestatus: "",
};
componentDidUpdate() {
axios
.get(
"https://localhost:44307/api/GetReservations/" +
`${this.state.activestatus}`
)
.then((response) => {
this.setState({
reservations: response.data,
});
});
}
}
showActive = (e) => {
e.preventDefault();
console.log(e.target.value);
this.setState({ activestatus: e.target.value });
};
render() {
let reservations = this.state.reservations.map((reservation) => {
return (
<tr>
<td>{reservation.Id}</td>
</tr>
);
});
return (
<div className="App container">
<Button
class="activity-button"
value={"?IsActive=0"}
id="active"
onClick={this.showActive}
>`

Related

React - why is my div not displayed on the page from my for loop function

I am writing a UI page to display a list of new messages, but I have gone wrong gin my code somewhere and not all of my page renders. I can't seem to find where.
My arrays correctly capture the data as I have tested this in console.log.
The text that should render on the page from the "displayNewMessage" doesn't work. Everything else renders.
Can anyone see where I have gone wrong please?
class Welcome extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
messageData: [],
newMessages: [],
isLoading: false
};
}
componentDidMount() {
this.setState({ isLoading: true });
this.setState({ userID: this.props.location.state });
const serachByUserId = this.props.location.state;
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url =
"my-url" +
serachByColleagueId;
fetch(proxyurl + url)
.then((res) => res.json())
.then((data) => this.setState({ data: data }))
.then(
fetch(
proxyurl +
"my-URL"
)
.then((res) => res.json())
.then((messageData) =>
this.setState(
{ messageData: messageData, isLoading: false },
() => {}
)
)
);
}
render() {
const { data, isLoading, messageData } = this.state;
if (isLoading) {
return (
<div className="pageLoading">
<p>Loading...</p>
</div>
);
}
return (
<div>
<div>
<p>
<strong>
Welcome {data.Forename} {data.Surname}
</strong>
</p>
</div>
<div className="InfoBox">
<p>
<strong>Message Backlog</strong>
</p>
<p className="helpText">
The below Orders have open chats awaiting a response. Click on
the order number to send and view messages.
</p>
</div>
{this.getMessages(messageData)}
</div>
);
}
getMessages(messageData) {
var newMessagesArray = [];
var latestMessageIndex;
var latestMessage;
messageData.message_Subjects.forEach(saveNewMessage);
function saveNewMessage(sub) {
console.log(sub);
latestMessageIndex = sub.message_Chain.length - 1;
latestMessage = sub.message_Chain[latestMessageIndex];
if (latestMessage.sentFromId.toString().length === 7) {
var message_Chain = {
dateTime: latestMessage.dateTime,
sentFromId: latestMessage.sentFromId,
messagebody: latestMessage.messageBody,
messageChainId: latestMessage.messageChainId,
};
var message_subject = {
userId: sub.userId,
subjectId: sub.messageSubjectId,
subject: sub.subject,
message_Chain: message_Chain,
};
newMessagesArray.push({ message_Subject: message_subject });
} else {
// do nothing
}
}
if (newMessagesArray.length > 0) {
return ( <div>{newMessagesArray.forEach(displayNewMessage)}</div>)
} else {
return <p>No New messages.</p>;
}
function displayNewMessage(arrayItem) {
console.log(arrayItem);
return (
<div>
<ul>
<li>Subject = {arrayItem.message_Subject.subject}</li>
<li>Order number = {arrayItem.message_Subject.orderNumber}</li>
<li>Date and Time = {arrayItem.message_Subject.dateTime}</li>
<li>
message = {arrayItem.message_Subject.message_Chain.messageBody}
</li>
<li>
sent by = {arrayItem.message_Subject.message_Chain.sentFromId}
</li>
</ul>
</div>
);
}
}
}
export default Welcome;
Found away around this not rendering on the page with no need for the displayNewMessage function.
if (newMessagesArray.length > 0) {
return (
newMessagesArray = newMessagesArray.map((item) =>
<li key={item.id}>Subject = {item.message_Subject.subject}</li>
<li> etc..... </li>
))
} else {
return <p>No New messages.</p>;
};

Api data returns to 0 after information is called (React)

I am fetching information about stocks in componentDidUpdate in React. The information that I want to fetch renders but after a few seconds the information reverts back to 0. I don't know why it is happening and I have tried to fetch it in componentDidMount first but the same thing keeps happening. I don't know how to go about solving this problem. Can someone point me in the right direction?
constructor(props) {
super(props);
this.state = {
userInput: '',
stockSymbol: [],
marketData: [],
isLoaded: false,
symbol1: [],
};
}
typeSymbol = e => {
this.setState({
userInput: e.target.value.toUpperCase(),
});
};
componentDidMount() {
const { userInput } = this.state;
const urls = [
`https://api.iextrading.com/1.0/ref-data/symbols`,
`https://api.iextrading.com/1.0/tops`,
];
let requests = urls.map(url => fetch(url));
Promise.all(requests)
.then(responses => {
return Promise.all(responses.map(response => response.json()));
})
.then(responses => {
this.setState({
stockSymbol: responses[0],
marketData: responses[1],
});
});
}
componentDidUpdate(prevProps, prevState, snapShot) {
const { userInput, symbol1 } = this.state;
if (prevState.userInput !== userInput) {
fetch(
`https://finnhub.io/api/v1/quote?symbol=${userInput}&token=brjo6knrh5r9g3ot7150`,
)
.then(res => res.json())
.then(responses => this.setState({ symbol1: responses }));
}
}
render() {
const { stockSymbol, userInput, marketData, symbol1 } = this.state;
const filteredSymbols = stockSymbol.filter(sym => sym.symbol === userInput);
const foundMarket = marketData.find(market => market.symbol === userInput);
const objData = () => {
for (const stockData in symbol1) {
console.log(`${stockData}: ${symbol1[stockData]}`);
}
};
objData();
const clock = new Date().toLocaleString();
return (
<div className="enterstock">
<div className="fields">
<span className="clock">{clock}</span>
<h1 className="title">Enter Stock Symbol</h1>
<input
type="text"
className="symfields"
name="symbolname"
onChange={this.typeSymbol}
/>
</div>
{filteredSymbols.map((stock, i) => {
return (
<div className="stockings">
<div className="named">
<h2 className="symbol">{this.state.userInput}</h2>
<h2 className=" name" key={i}>
{stock.name}
</h2>
</div>
{
<h2 className="stocked price" key={i}>
Price: {symbol1.c}
</h2>
}
</div>
);
})}
,
</div>
);
}

React context: send input data to another component

I have 3 components:
Search.js, Customers.js and Customer.js
In Search.js I have an input field. I want to send whatever value entered in the field over to the Customer.js component. I thought this would be straightforward, but I was wrong ...
I have also a context.js component that stores state for the application (I don't want to use redux because I don't know it yet).
Sorry but this is gonna be a long post as I want to give the background for this specific situation:
context.js
const Context = React.createContext();
const reducer = (state, action) => {
switch (action.type) {
case "SEARCH_CUSTOMERS":
return {
...state,
customer_list: action.payload,
firstName: ''
};
default:
return state;
}
};
export class Provider extends Component {
state = {
customer_list: [],
firstName: "",
dispatch: action => this.setState(state => reducer(state, action))
};
componentDidMount() {
axios
.get("/api")
.then(res => {
console.log(res.data);
this.setState({ customer_list: res.data });
})
.catch(error => console.log(error));
}
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
);
}
}
export const Consumer = Context.Consumer;
Search.js: the input value I want to send to Customer is 'firstName'
class Search extends Component {
state = {
firstName: ""
};
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
findCustomer = (dispatch, e) => {
e.preventDefault();
axios
.get("/api/customers", {
params: {
firstName: this.state.firstName,
}
})
.then(res => {
dispatch({
type: "SEARCH_CUSTOMERS",
payload: res.data
});
this.setState({ firstName: "" });
});
};
return (
<Consumer>
{value => {
const { dispatch } = value;
return (
<form onSubmit={this.findCustomer.bind(this, dispatch)}>
<div className="form-group">
<input
ref={input => {
this.nameInput = input;
}}
type="text"
name="firstName"
value={this.state.firstName}
onChange={this.onChange}
/>
the Customers.js:
class Customers extends Component {
render() {
const key = Date.now();
return (
<Consumer>
{value => {
const { customer_list} = value;
if (customer_list === undefined || customer_list.length === 0) {
return <Spinner />;
} else {
return (
<React.Fragment>
<h3 className="text-center mb-4">{heading}</h3>
<div className="row">
{customer_list.map(item => (
<Customer key={item.key} customer={item} />
))}
</div>
</React.Fragment>
);
}
}}
</Consumer>
);
}
}
export default Customers;
and Finally theCustomer.js: this is where I want the input value to be displayed:
const Customer = props => {
const { customer } = props;
return (
<div className="col-md-12">
<div className="card-body">
<strong>{customer.firstName}</strong> // not working
...
}
the {customer.firstName} does not show the value.
Is is necessary to go through the intermediate Customers.js component to pass the input value?
I would like to keep the architecture as is (with the context.js) and display the value in the Customer.js component.

How to setState to answer from APi and use map

Im trying to create recipes searcher. In App.js I receive query from search input from another component and I want to setState to answer from APi. Console.log from callback in setState shows updated state but the state is not updated. I need setState updaed so I can use map on it and display list of recipes in render. It gives me error map is not a function because this.state.recipesList is still empty. Anyone can help me ?
class App extends Component {
state = {
query: "",
recipesList: []
};
getQuery = query => {
const key = "2889f0d3f51281eea62fa6726e16991e";
const URL = `https://www.food2fork.com/api/search?key=${key}&q=${query}`;
fetch(URL)
.then(res => res.json())
.then(res => {
this.setState(
{
recipesList: res
},
() => {
console.log(this.state.recipesList);
}
);
});
console.log(this.state.recipesList);
};
render() {
const test = this.state.recipesList.map(item => {
return (
<div className="recispesList">
<h1>{item.title}</h1>
</div>
);
});
return (
<div className="App">
<Search query={this.getQuery} />
<div className="contentWrapper">{}</div>
</div>
);
}
}
Search component:
class Search extends Component {
state = {
searchValue: ""
};
handleChange = val => {
let searchValue = val.target.value;
this.setState({
searchValue
});
};
handleSubmit = e => {
e.preventDefault();
this.setState({
searchValue: ""
});
this.props.query(this.state.searchValue);
};
render() {
return (
<div className="searchWrapper">
<form onSubmit={this.handleSubmit}>
<input onChange={this.handleChange} value={this.state.searchValue} />
<button />
</form>
</div>
);
}
}
export default Search;
It seems that instead of directly assigning the whole response to recipesList:
this.setState(
{
recipesList: res
},
() => {
console.log(this.state.recipesList);
}
);
you need to get recipes array first via res.recipes:
this.setState(
{
recipesList: res.recipes
},
() => {
console.log(this.state.recipesList);
}
);

How to Create a Search Field in ReactJS

I'm new to react, and I'm working on a small project that uses a search bar to find data that I've gotten from my database.
The code for this component is below:
import React, { Component } from 'react';
class BodyData extends Component {
state = {
query: '',
data: [],
}
handleInputChange = () => {
this.setState({
query: this.search.value
})
this.filterArray();
}
getData = () => {
fetch(`http://localhost:4000/restaurants`)
.then(response => response.json())
.then(responseData => {
// console.log(responseData)
this.setState({
data:responseData
})
})
}
filterArray = () => {
var searchString = this.state.query;
var responseData = this.state.data
if(searchString.length > 0){
// console.log(responseData[i].name);
responseData = responseData.filter(l => {
console.log( l.name.toLowerCase().match(searchString));
})
}
}
componentWillMount() {
this.getData();
}
render() {
return (
<div className="searchForm">
<form>
<input type="text" id="filter" placeholder="Search for..." ref={input => this.search = input} onChange={this.handleInputChange}/>
</form>
<div>
{
this.state.data.map((i) =>
<p>{i.name}</p>
)
}
</div>
</div>
)
}
}
export default BodyData;
So basically, I want to update the state as I type in the query text, and have the restaurant names I've mapped be reduced till a match is found.
From what I understood, this.state.data will be filtered as I type in my query in the search bar. However when I map out this.state.data, I get the whole list of restaurants instead of what I want to see.
Ive been through a bunch of tutes, and I'm not exactly sure how to go about doing that.
Can anyone help me with this please? Any other comments on the code are also welcome. I'm here to learn :)
Thank you!
You could keep an additional piece of state called e.g. filteredData that contains all elements in data that include your query in the name, and then render that.
Example
class BodyData extends React.Component {
state = {
query: "",
data: [],
filteredData: []
};
handleInputChange = event => {
const query = event.target.value;
this.setState(prevState => {
const filteredData = prevState.data.filter(element => {
return element.name.toLowerCase().includes(query.toLowerCase());
});
return {
query,
filteredData
};
});
};
getData = () => {
fetch(`http://localhost:4000/restaurants`)
.then(response => response.json())
.then(data => {
const { query } = this.state;
const filteredData = data.filter(element => {
return element.name.toLowerCase().includes(query.toLowerCase());
});
this.setState({
data,
filteredData
});
});
};
componentWillMount() {
this.getData();
}
render() {
return (
<div className="searchForm">
<form>
<input
placeholder="Search for..."
value={this.state.query}
onChange={this.handleInputChange}
/>
</form>
<div>{this.state.filteredData.map(i => <p>{i.name}</p>)}</div>
</div>
);
}
}
Here is the code that will work for you
import React, { Component } from 'react';
class BodyData extends Component {
state = {
query: '',
data: [],
searchString:[]
}
handleInputChange = (event) => {
this.setState({
query: event.target.value
},()=>{
this.filterArray();
})
}
getData = () => {
fetch(`http://localhost:4000/restaurants`)
.then(response => response.json())
.then(responseData => {
// console.log(responseData)
this.setState({
data:responseData,
searchString:responseData
})
})
}
filterArray = () => {
let searchString = this.state.query;
let responseData = this.state.data;
if(searchString.length > 0){
// console.log(responseData[i].name);
responseData = responseData.filter(searchString);
this.setState({
responseData
})
}
}
componentWillMount() {
this.getData();
}
render() {
return (
<div className="searchForm">
<form>
<input type="text" id="filter" placeholder="Search for..." onChange={this.handleInputChange}/>
</form>
<div>
{
this.state.responseData.map((i) =>
<p>{i.name}</p>
)
}
</div>
</div>
)
}
}
export default BodyData;
There are few changes which is needed.
Set State is worked asynchronous.SO, to avoid it use arrow function when you need to do something immediately after set state.
there are 2 different keyword in es6 instead of var. Let and Const . use them instead of var.
There is no need of ref in input. you can directly get value of input by event.target.value
Enjoy Coding!!
setState method is asynchronous and it has second parameter - callback that is called when the state is applied.
You need to change handleInputChange methods.
handleInputChange = () => {
this.setState({
query: this.search.value
}, this.filterArray)
}
Few pointers I'll like to show-
setState({}) function is asynchronous, you'll have to either use functional setState and call filteredArray method as a callback. Or, call filteredArray at render, which is where your values will be updated and be reflected.
Your filterArray method is not returning / setting the filtered list of data. So what you type, even though it is getting filtered, it is not getting set / returned anywhere.

Resources