This is the code my react component:
class App extends React.Component {
constructor() {
super();
}
update(e) {
axios.get('https://myjsonurl.com', {
params: {
phrase: e.target.value
}
}).then(function (response) {
console.log(response.data);
}).catch(function (err) {
console.log(err);
});
}
render() {
return (
<div>
<input type="text" onChange={this.update} />
</div>
)
}
}
By searching I get correct results in console of my browser. Can someone give me some tipps how can I insert this data in a list?
Is there to create a new component and tell in response to use this component?
Create a state variable and save the response inside that. Call a function from render method that will create the list from that response.
Bind the update method inside constructor.
Like this:
class App extends React.Component {
constructor() {
super();
this.state = {
data: []
}
this.update = this.update.bind(this); //bind the method
}
update(e) {
axios.get('https://myjsonurl.com', {
params: {
phrase: e.target.value
}
}).then((response) => {
this.setState({data: response.data}); //set the response in state
}).catch((err) => {
console.log(err);
});
}
createList(){
if(!this.state.data.length) return null;
return <ul>
{this.state.data.map((el, index) => <li key={index}> {el.KeyName} </li>)}
</ul>
}
render() {
return (
<div>
<input type="text" onChange={this.update} />
{this.createList()}
</div>
)
}
}
Note: Replace el.KeyName with actual key that you want to show, and assign some unique value to key key={index} i used index because don't know the details about the response.
Related
I have a react JSX component that makes an api call to the backend and fetches the data I require. This data is currently inside a react-select tag which allows me to display all the options inside a dropdown. I'm trying now to use this dropdown to render the selection using charts, specifically react-chartjs-2. I've been trying for quite a while but I honestly am at my wits end.
Here's what the api call with the select looks like:
export default class ------ extends component{
constructor(props, context) {
super(props, context);
this.state = {
selectedOption: {},
};
}
fetchData = (inputValue, callback) => {
setTimeout(() => {
fetch(
"api" +
inputValue,
{
method: "GET",
}
)
.then((resp) => {
return resp.json();
})
.then((data) => {
const tempArray = [];
if (data) {
if (data.length) {
data.forEach((element) => {
tempArray.push({
label: `${element.campo}`,
value: element.valor,
});
});
} else {
tempArray.push({
label: `${data.campo}`,
value: data.valor,
});
}
}
callback(tempArray);
})
.catch((error) => {
console.log(error, "error");
});
}, 1000);
};
onSearchChange = (selectedOption) => {
if (selectedOption) {
this.setState({
selectedOption,
});
}
};
Here's the actual select element and the chart inside the return section
render(){
return(
<AsyncSelect
id="valx"
value={this.state.selectedOption}
loadOptions={this.fetchData}
placeholder="placehold"
onChange={(e) => {
this.onSearchChange(e);
}}
defaultOptions={true}
/>
<div class="charts">
<Bar
id="MyBarChart"
data={{}}
options={{}}
/>
<Pie
id="MyPieChart"
data={{}}
options={{}}
/>
</div>
I have a really long way to go when it comes to React, I'm sure the solution will turn out to be rather simple. Any and all help is welcome, and thanks in advance.
I have created a menu, with a submenu and a third child. So far I had it done simply with a json in local const data that is now commented. I need that from now on the data is collected from my json but I do not know how to do it. As it is now I get the following error: 'data' is not defined ( in my render)
class Nav extends Component {
constructor(props){
super(props)
this.state = {
navigation:[]
}
}
componentWillMount() {
fetch('json_menuFIN.php')
.then(response => response.json())
.then(data =>{
this.setState({navigation: data });
console.log( data)
})
}
render(){
const { data = null } = this.state.navigation;
if ( this.state.navigation && !this.state.navigation.length ) { // or wherever your data may be
return null;
}
return (
<Menu data={this.state.navigation}/>
)
}
}
const renderMenu = items => {
return <ul>
{ items.map(i => {
return <li>
<a href={i.link}>{ i.title }</a>
{ i.menu && renderMenu(i.menu) }
</li>
})}
</ul>
}
const Menu = ({ data }) => {
return <nav>
<h2>{ data.title }</h2>
{ renderMenu(data.menu) }
</nav>
}
I do not know what else to do to make it work with what I have. Thank you very much for the help.
Your navigation property in state has no title and menu properties, so you pass an empty array to Menu component. That's why you have an error Cannot read property 'map' of undefined. You should change your state initialization in constructor.
class Nav extends Component {
constructor(props){
super(props);
this.state = {
navigation: {//<-- change an empty array to object with a structure like a response from the server
menu: [],
title: ''
}
}
}
//...
render(){
return (
<Menu data={this.state.navigation} />
)
}
}
Don't use componentWillMount as it is deprecated and will soon disappear, the correct way is to use componentDidMount method along with a state variable and a test in your render.
this.state = {
navigation: [],
init: false
}
componentDidMount() {
fetch('json_menuFIN.php')
.then(response => response.json())
.then(data => {
this.setState({ navigation: data, init: true });
console.log( data)
})
}
Also, you cannot extract the data variable from your navigation variable in the state, navigation has been defined with your data response, so use it directly.
render() {
const { navigation, init } = this.state;
if(!init) return null
return (
<Menu data={navigation}/>
)
}
I assume that navigation is always an array, whatever you do with it.
The parent component Dashboard holds the state for every ListItem I add to my Watchlist. Unfortunately, every time I am adding an Item, it gets added to the DB, but only shows up when I refresh the browser.
class UserDashboard extends React.Component {
state = {
data: []
}
componentWillMount() {
authService.checkAuthentication(this.props);
}
isLoggedIn = () => {
return authService.authenticated()
}
getAllCoins = () => {
//fetches from backend API
}
addWishlist = () => {
this.getAllCoins()
.then(things => {
this.setState({
data: things
})
})
console.log("CHILD WAS CLICKED")
}
componentDidMount() {
this.getAllCoins()
.then(things => {
this.setState({
data: things
})
})
}
render() {
return (
<div className="dashboard">
<h1>HI, WELCOME TO USER DASHBOARD</h1>
<SearchBar
addWishlist={this.addWishlist}
/>
<UserWatchlist
data={this.state.data}
/>
</div>
);
}
}
The User Watchlist:
class UserWatchlist extends React.Component {
constructor(props) {
super(props)
}
// componentDidUpdate(prevProps) {
// if (this.props.data !== prevProps.data) {
// console.log("CURRENT", this.props.data)
// console.log("PREVs", prevProps.data)
// }
// }
render() {
return (
<div>
<h2>These are tssssyou are watching:</h2>
<ul className="coin-watchlist">
{
this.props.data.map((coin, idx) => {
return <ListItem key={idx}
coin={coin.ticker}
price={coin.price}
/>
})
}
</ul>
</div>
)
}
}
The search Bar that shows potential Items to watch over:
class SearchBar extends React.Component {
constructor(props) {
super(props)
this.state = {
coins: [],
searchValue: ""
}
}
searchHandler = e => {
e.preventDefault()
const value = e.target.value
this.setState({
searchValue: value
});
if (value === "") {
this.setState({
coins: []
})
} else {
this.getInfo()
}
}
getInfo = () => {
// Searches the API
}
addWishlist = () => {
this.props.addWishlist();
}
render() {
const {coins, searchValue} = this.state
return (
<div className="coin-search">
<form>
<input
type="text"
className="prompt"
placeholder="Search by ticker symbol"
value={searchValue}
onChange={this.searchHandler}
/>
</form>
<ul className="search-suggestions">
{
coins.filter(searchingFor(searchValue)).map( coin =>
<Currency
coin={coin}
addWishlist={this.addWishlist}
/>
)
}
</ul>
</div>
);
}
}
And the actual Currency that gets clicked to be added:
class Currency extends React.Component {
addToWatchlist = () => {
// POST to backend DB to save
};
fetch("/api/add-coin", settings)
.catch(err => {
return err
})
}
clickHandler = () => {
this.addToWatchlist()
this.props.addWishlist()
}
render() {
return(
<div className="search-results">
<li>
<h3> { this.props.coin.currency } </h3>
<button
className="add-to-list"
onClick={this.clickHandler}
>
+ to Watchlist
</button>
</li>
</div>
)
}
}
As you can see, I am sending props down all the way down to child. When I click the button to Add to Watchlist, I see the console.log message appear, saying "CHILD WAS CLICKED". I've even tried just calling the method to fetch from backend API again.
Also, in UserWatchlist, I've tried a componentDidUpdate, but both prevProps and this.props show the very same array of data. Somewhere in the chain, my data is getting lost.
This is also my first time posting a question here, so if it can be improved, I am happy to add extra details and contribute something to this community
You probably forgot to wait for addToWatchlist to complete:
addToWatchlist = () => {
// POST to backend DB to save
return fetch("/api/add-coin", settings)
.catch(err => {
return err
})
}
clickHandler = () => {
this.addToWatchlist().then(() => {
this.props.addWishlist()
})
}
I have the following structure of components in the application:
class Car extends Component {
constructor() {
super();
this.state = {
cars: [],
...
}
}
componentDidMount() {
axios.get('/api/cars')
.then((response) => {
this.setState({cars: response.data});
console.log('cars: ', cars);
}).catch(err => {
console.log('CAUGHT IT! -> ', err);
});
}
render() {
return (
...
<CarAddNew />
<CarSearch />
<CarList cars={this.state.cars} />
)
}
}
and then
export default class CarSearch extends Component {
constructor(){...}
handleSearchSubmit(e) {
e.preventDefault();
..
axios.post('/api/cars/search', searchCars)
.then(response => {
console.log('response.data: ', response.data);
})
}
render() {
return(
... search form ...
)
}
When I search data in the database through the CarSearch component, it will fetch and load the right data, that's great. However, how do I pass this "new" found data to the CarList component, so I can display the on the page?
What I would do is the following:
class Car extends Component {
constructor() {
super();
this.state = {
cars: [],
...
}
}
componentDidMount() {
axios.get('/api/cars')
.then((response) => {
this.setState({cars: response.data});
console.log('cars: ', cars);
}).catch(err => {
console.log('CAUGHT IT! -> ', err);
});
}
handleSearch = () => {
axios.post('/api/cars/search', searchCars) // not sure where you are getting searchCars from, but you should get the idea
.then(response => {
this.setState({cars: response.data})
console.log('response.data: ', response.data);
})
}
render() {
return (
...
<CarAddNew />
<CarSearch onSearch={this.handleSearch} />
<CarList cars={this.state.cars} />
)
}
}
export default class CarSearch extends Component {
constructor(){...}
handleSearchSubmit(e) {
e.preventDefault();
this.props.onSearch() // I'm assuming you probably want to pass something here
}
render() {
return(
... search form ...
)
}
One option is to propagate the data up through a prop on CarSearch. Consider the (truncated) example...
handleSearchSubmit(e) {
e.preventDefault();
axios.post('/api/cars/search', searchCars).then(response => {
this.props.onData(response.data);
});
}
where, onData calls back up to the following (then later setting state)...
constructor() {
// [...]
this.onSearchResult = this.onSearchResult.bind(this);
}
onSearchResult(cars) {
this.setState({cars}); // results from CarSearch
}
render() {
return (
<CarAddNew />
<CarSearch
onData={this.onSearchResult} />
<CarList
cars={this.state.cars} />
)
}
I am newbie to React. In my CRUD aplication I have a Main component. Then in the List Component I make an API call to load item from server. The problem is that after a new item submitting in Create component I need to refresh my List in order to see a new item added. What is the possible non-flux solution?
Main.jsx
export default class Main extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
showModal: false,
};
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
openModal() {
this.setState({showModal: true});
}
closeModal() {
this.setState({showModal: false});
}
render() {
return (
<div>
<div class="navbar">
<div class="nav-item"onClick={this.openModal}>Create</div>
</div>
<div class="modal" show={this.state.showModal} onHide={this.closeModal}>
<div class="modal-body">
<Create onItemCreate={this.closeModal}/>
</div>
</div>
<List />
</div>
);
}
}
UPDATE:
List.jsx
export default class List extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
items: []
};
}
refreshList() {
$.ajax({
url : apiPrefix,
dataType : 'json',
type : 'GET',
success: data => {
this.setState({items: data.items});
},
error: (xhr, status, err) => {
console.error(apiPrefix, status, err.toString());
}
});
}
render() {
if( this.state.findings === undefined ) {
return <div>Loading...</div>
} else {
return(
<div>
<div>
{
this.state.findings.map((item) => {
return <Item key={item._id} item={item} />
})
}
</div>
</div>
);
}
}
componentWillMount() {
this.refreshList();
}
}
Create.jsx
export default class Create extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
};
}
// Perform a post request to save a formData
onSubmit({formData}) {
formData.type = this.state.selectValue;
axios.post(apiPrefix, formData)
.then(() => {
this.closeModal();
// THIS LIST NEED TO BE REFRESHED
});
}
closeModal() {
this.props.onFindingCreated();
}
render() {
return (
<div>
<div class="form"></div>
</div>
)
}
}
when your control reaches to Create page you can check it conditionally in render as:-
Create a variable that will store your state initially when your create page will be loaded first
render{
if(var==null) //will load your var when this class will run first
{
var=this.props.onItemCreate.showModal
return()..
}
else if(this.props.onItemCreate.showModal!=var and var!=null)
{
var=[] //empty variable and update it to new props
var=this.props.onItemCreate.showModal
}
}
Or
you can use
componentWillReceiveProps in your child class and check if props has been updated then simply set your state to that props and hence your list also