Hello im new in React and im trying to play a little with React but heres one point i dont understand.
at first, fetch with axios data who return my data, the following, then i try to put them into the input fields, value(and is readonly), defaultValue is better, now i have the problem, i see nothing, the value exists when i view with firebug, the strange thing is, when i add a unneed character the input get filled by my wanted but not by default.
The very strange thing is, when i put everything in a Array and does a map function over it i have the value
the json code
{"firma":"hallo","strasse":"musterweg 7","plz":"01662"}
the js code
import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
class Testx extends React.Component {
constructor(props) {
super(props);
this.state = {
data:[]
};
}
componentDidMount(){
var self = this;
axios.get('http://localhost/index.php')
.then(function (response) {
self.setState({ data: response.data});
})
.catch(function (error) {
console.log(error);
});
}
render() {
return (
<div>
<input type="text" defaultValue={this.state.data.firma}/>
</div>
);
}
}
ReactDOM.render(<Testx/>, document.getElementById('hello'));
You need to wait until the data comes by showing something loading.
import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
class Testx extends React.Component {
constructor(props) {
super(props);
this.state = {
data:{}
};
}
componentDidMount(){
var self = this;
axios.get('http://localhost/index.php')
.then(function (response) {
self.setState({ data: response.data});
})
.catch(function (error) {
console.log(error);
});
}
render() {
const { data }= this.state;
if(data.firma) {
return (<div>
<input type="text" defaultValue={data.firma}/>
</div>);
}
return <div>loading...</div>;
}
}
ReactDOM.render(<Testx/>, document.getElementById('hello'));
Initially, your data state is in Array format. So this.state.data.firma doesnt work. Instead make it as empty object {}.
import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
class Testx extends React.Component {
constructor(props) {
super(props);
this.state = {
data: {}
};
}
componentDidMount() {
var self = this;
axios.get('http://localhost/index.php')
.then(function (response) {
self.setState({ data: response.data});
})
.catch(function (error) {
console.log(error);
});
}
render() {
return <div>
<input type="text" defaultValue={this.state.data.firma}/>
</div>
}
}
ReactDOM.render(<Testx/>, document.getElementById('hello'));
The "code style" is outdated. Try to work with arrow functions which bind your functions, such as setState. Or bind your functions once in your constructor like this.myFunction = myFunction.bind(this) so you are able to access this. I already commented that this.state.data is declared as an array. Either change it to be an object or access an object by a specific index.
class Testx extends React.Component {
constructor(props) {
super(props);
this.state = {
data:{}
};
}
componentDidMount = () => { //Note the arrow function to bind this function
//Functions like componentDidMount are usually already bound
axios.get('http://localhost/index.php')
.then((response) => {
this.setState({ data: response.data});
})
.catch((error) => {
console.log(error);
});
}
render() {
return (
<div>
<input type="text" defaultValue={this.state.data.firma}/>
</div>
);
}
}
If your response is an array instead of an object, then try to access firma like this: this.state.data[index].firma
thanks all, special for the tips and tricks and how i can do thinks better, my questions is solved, big thanks to all for helping me in under 15 min happy
im now also found a way playing with https://facebook.github.io/react/docs/forms.html and set my state with
handleChange(event) {
var tmp = this.state.data;
tmp[event.target.id] = event.target.value
this.setState({data: tmp});
}
with modding my render
<input type="text" id="firma" value={this.state.data.firma} onChange={this.handleChange} />
Related
I am getting the following error in my code. Can you please help me to understand the issue. I have included my page component and task list component.
TypeError: this.state.tasks.map is not a function
Page Show.js
import React, { Component } from 'react';
import axios from 'axios';
import TasksList from './TasksList';
export default class Show extends Component {
constructor(props) {
super(props);
this.state = {tasks: [] };
}
componentDidMount(){
axios.post('http://mohamed-bouhlel.com/p5/todolist/todophp/show.php')
.then(response => {
this.setState({ tasks: response.data });
})
.catch(function (error) {
console.log(error);
})
}
tasksList(){
return this.state.tasks.map(function(object,i){
return <TasksList obj = {object} key={i} />;
});
}
render() {
return (
<div>
{ this.tasksList() }
</div>
)
}
}
Page TasksList.js
import React, { Component } from 'react';
export default class TasksList extends Component {
render() {
return (
<div>
<div>{this.props.obj.task}</div>
</div>
)
}
}
Using a GET request and correct protocol (https vs http) seems to resolve the issue.
axios.get("https://mohamed-bouhlel.com/p5/todolist/todophp/show.php")
Response.data is not an array and basically you can't call map on a non-array.
I suggest console.log(response.data) to check the data type.
And I guess maybe you're doing a axios.post instead of a correct axios.get. log the response.data and you'll find out.
I have two components: which takes value from an input field. Second component is which I fetch api data. The problem is that I want to get the value from GetSearch as the value i search the API in Pexels.
I have tried to change my code multiple times. I just cant understand how it is supposed to be done, and how should I actually communicate together with my components.
import React from "react";
class GetSearch extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
var PassValue = React.CreateClass({
render: function() {
return (
<p>{this.state.value}</p>
);
},
});
return (
<form className="search-form">
<input
type="text"
placeholder="Search for images"
value={this.state.value}
onChange={this.handleChange}/>
<input type="submit"/>
</form>
);
}
}
export default GetSearch
import React, { Component } from 'react'
export default class Pexels extends Component {
componentDidMount(){
let query = "water"
const url = `https://api.pexels.com/v1/search?query=${query}e+query&per_page=15&page=1`
const api_key = "xxxxxxxxxxxx"
fetch(url, {
method: 'GET',
headers: new Headers({
'Authorization': api_key
})
})
.then(response => response.json())
.then(data => {
console.log(data)
})
.catch(error => console.error(error))
}
render() {
return (
<h1>Hello</h1>)
}
}
So as you can see now: Pexels sends a get request with the value of water: let query = "water", which works fine. But I need the value from
this.state.value in the GetSearch component
First, you need to create a parent class. Then You need to pass callback functions to the children as props. Here GetSearch component can be your child class. After you click search button your main class method will notify that change. Then create your logic as you want.
Follow this example code. thanks
Parent Component
var ParentComponent = React.createClass({
update: function() {
console.log("updated!");
},
render: function() {
<ChildComponent callBack={this.update} />
}
})
Child Component
var ChildComponent = React.createClass({
preupdate: function() {
console.log("pre update done!");
},
render: function() {
<button onClick={this.props.callback}>click to update parent</button>
}
})
You may need a store(just a function) to fetch url data rather than in a UI component Pexels.
In GetSearch invoke the store function with input as parameter and return a promise, and get data in callback.
After get the comments array from post component and pass it to comments component
the logs start to show the error in the screenshot below
the components are:
import React, { Component } from "react";
import axios from "axios";
import Comments from "../components/comments";
class Article extends Component {
constructor(props) {
super(props);
this.state = {
title: "",
error: "",
comment: ""
};
}
componentDidMount() {
this.getComments();
}
getComments = () => {
const {
match: { params }
} = this.props;
return axios
.get(`/articles/${params.id}/comments`, {
headers: {
Accept: "application/json",
"Content-Type": "application/json",
}
})
.then(response => {
return response.json();
})
.then(response => this.setState({ comments: response.comments }))
.catch(error =>
this.setState({
error
})
);
};
render() {
return (
<div>
{this.state.title}
<div>
<h2>Comments</h2>
<Comments
getComments={this.getComments}
/>
</div>
</div>
);
}
}
export default Article;
and Comments component
import React, { Component } from "react";
import PropTypes from "prop-types";
import Comment from "./comment";
import axios from "axios";
import Article from "../screens/article";
class Comments extends Component {
constructor(props) {
super(props);
this.state = {
comments: [],
comment: "",
error: ""
};
this.load = this.load.bind(this);
this.comment = this.comment.bind(this);
}
componentDidMount() {
this.load();
}
load() {
return this.props.getComments().then(comments => {
this.setState({ comments });
return comments;
});
}
comment() {
return this.props.submitComment().then(comment => {
this.setState({ comment }).then(this.load);
});
}
render() {
const { comments } = this.state;
return (
<div>
{comments.map(comment => (
<Comment key={comment.id} commment={comment} />
))}
</div>
);
}
}
export default Comments;
so, I've tried to pass it by props, and set the state on comments component.
and instead of use just comments.map I've tried to use this.state but show the same error in the logs.
So, someone please would like to clarify this kind of issue?
seems pretty usual issue when working with react.
If an error occurs you do:
.catch(error => this.setState({ error }) );
which makes the chained promise resolve to undefined and that is used as comments in the Comments state. So you have to return an array from the catch:
.catch(error => {
this.setState({ error });
return [];
});
Additionally it woupd make sense to not render the Comments child at all if the parents state contains an error.
The other way is checking whether it’s an array and if so check it’s length and then do .map. You have initialized comments to empty array so we don’t need to check whether it’s an array but to be on safer side if api response receives an object then it will set object to comments so in that case comments.length won’t work so it’s good to check whether it’s an array or not.
Below change would work
<div>
{Array.isArray(comments) && comments.length>0 && comments.map(comment => (
<Comment key={comment.id} commment={comment} />
))}
</div>
The first time the comments component renders there was no response yet so comments were undefined.
import React, { Component } from "react";
import PropTypes from "prop-types";
import Comment from "./comment";
import axios from "axios";
import Article from "../screens/article";
class Comments extends Component {
constructor(props) {
super(props);
this.state = {
comments: [],
comment: "",
error: ""
};
this.load = this.load.bind(this);
this.comment = this.comment.bind(this);
}
componentDidMount() {
this.load();
}
load() {
return this.props.getComments().then(comments => {
this.setState({ comments });
return comments;
});
}
comment() {
return this.props.submitComment().then(comment => {
this.setState({ comment }).then(this.load);
});
}
render() {
const { comments } = this.state;
if (!comments) return <p>No comments Available</p>;
return (
<div>
{comments.map(comment => (
<Comment key={comment.id} commment={comment} />
))}
</div>
);
}
}
export default Comments;
I have a component, which has to download a JSON file and then iterate over it and display each element from the JSON on the screen.
I'm kinda new with React, used to be ng dev. In Angular, I used to do it with lifecycle hooks, e.g. ngOnInit/ngAfterViewInit (get some JSON file and then lunch the iteration func). How can I achieve it in React? Is it possible to reach it with lifecycle hooks, like ComponentWillMount or ComponentDidMount.
My code (it's surely wrong):
export default class ExampleClass extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
}
}
componentWillMount(){
getData();
}
render() {
return (
<ul>
{this.state.data.map((v, i) => <li key={i}>{v}</li>)}
</ul>
)
};
}
const getData = () => {
axios.get(//someURL//)
.then(function (response) {
this.setState({data: response.data});
})
.catch(function (error) {
console.log(error);
})
};
How to force React to get the JSON before rendering the component?
Thank you so much.
Making an AJAX request in ComponentWillMount works. https://facebook.github.io/react/docs/react-component.html#componentwillmount
You could also just work that logic into your constructor depending on your exact needs.
https://facebook.github.io/react/docs/react-component.html#constructor
export default class ExampleClass extends React.Component {
constructor(props) {
super(props)
this.state = {
data: [],
}
axios.get(/*someURL*/)
.then(function (response) {
this.setState({data: response.data});
})
.catch(function (error) {
console.log(error);
})
}
}
You can do a simple if statement in your render function.
render () {
if (Boolean(this.state.data.length)) {
return <ul>{this.state.data.map((v, i) => <li key={i}>{v}</li>)}</ul>
}
return null
}
You can also use a higher order component to do the same thing.
const renderIfData = WrappedComponent => class RenderIfData extends Component {
state = {
data: []
}
componentWillMount() {
fetchData()
}
render() {
if (Boolean(this.state.data.length)) {
return <WrappedComponent {...this.state} />
}
return null
}
}
Then you can wrap the presentational layer with the HOC.
renderIfData(ExampleClass)
Not sure what version of React you are using but you may need to use <noscript> instead of null.
This is essentially preventing your component from rendering until it has all the data.
I'm pulling data from my my database which needs to be available prior to the mounting of the component in order for the page to be populated with the componentDidMount() lifecycle method. I've verified that if i remove the setState and console.log my data, it does fetch from the DB as expected, but when I try to assign the data to my state variable, it return a error stating Unable to get property 'setState' of undefined or null reference within my componentWillMount() lifecycle method. I've listed my ReactJS code below.
import React, { Component, PropTypes } from 'react';
import Picture from '../../components/picture.jsx';
import { browserHistory } from 'react-router';
export default class Products extends Component {
constructor(props) {
super(props);
this.state = {clothingData: ''};
}
componentWillMount(){
fetch('/t')
.then(function(result){
return result.json();
})
.then(function(re){
this.setState({ clothingData: re });
console.log(this.state.clothingData);
})
.catch(function(error){
console.log(error);
});
}
componentDidMount(){
//empty for now
}
render(){
var MyArray = ['justin','tiffany','joe','john','karissa','pam','joseph','sean','kim'];
var imageSrc = ['http://placehold.it/249x373','http://placehold.it/249x373','http://placehold.it/249x373','http://placehold.it/249x373','http://placehold.it/249x373',
'http://placehold.it/249x373', 'http://placehold.it/249x373', 'http://placehold.it/249x373'];
return (
<div>
<Picture src = {imageSrc} onClick = { () => {browserHistory.push('/Product'); }} name = {MyArray} amount = {8} />
</div>
);
}
}
The problem is that this is being reassigned from the component instance to the function instance/global object.
componentWillMount() {
fetch('/t')
.then((result) => {
return result.json();
})
.then((re) => {
this.setState({ clothingData: re });
console.log(this.state.clothingData);
})
.catch(function(error){
console.log(error);
});
}
will work just fine since the arrow function will ensure that the this is bound to the component instance so this.setState will actually be defined. Whereas what you have the this is being set to the global object which does not have a property of setState