So I'm creating a simple React app that fetches data from a JSON API server and displays it in a table. Here is the code for the main component:
import React, {Component} from "react"
import Table from "./Table.js"
class Main extends Component{
constructor(props) {
super(props);
this.state = {
array: null
}
}
render(){
return(
<div>
<Table array={this.state.array} />
</div>
)
}
componentDidMount() {
console.log("Checking");
fetch("https://api.myjson.com/bins/1exld0")
.then(response => response.json())
.then(data => {
console.log(data);
this.setState({ array: data })
});
}
}
export default Main;
However when I run the app the table is not being rendered. This has something to do with the componentDidMount function not working properly because I have a line of code:
console.log("Checking")
and the console doesn't log anything.
Can anyone help?
Edit: Here are the Table and TableRow components:
import React, {Component} from "react"
import TableRow from "./TableRow.js";
class Table extends Component{
constructor(props){
super(props);
this.state={
}
}
render(){
var self=this;
var items=this.props.array.map(function(item, index){
return <TableRow obj={item} key={index}/>
})
return(
<table>
{items}
</table>
)
}
}
export default Table
/
import React, {Component} from "react"
class TableRow extends Component{
constructor(props){
super(props);
this.state={
}
}
render(){
return(
<tr><td>{this.props.obj.color}</td><td>{this.props.obj.value}</td></tr>
)
}
}
export default TableRow
And here is the error that I am being given when I run the app in the browser:
TypeError: Cannot read property 'map' of null:
var items=this.props.array.map(function(item, index){
Set the array to the empty array instead of null in the Main constructor. There will be an initial render cycle before the async data is loaded, and that crashes since you cannot map over a null array.
move componentDidMount() out of the render() method , that will fix it
Related
I have two components. The first has state initialized:
import React from 'react';
class One extends React.Component {
constructor(props) {
super(props);
this.state = {
data: 'hi'
}
}
render() {
return (
<div prop={this.state.data}>{this.state.data}</div>
);
}
}
export default One;
import React from 'react';
class Two extends React.Component {
render() {
return (
<div>{this.prop}</div>
);
}
}
export default Two;
The first component prints out the state of data. How would I pass that value into my second component as a read only value and render it?
To pass the value in the second component, you have to first import it in your first component and pass the value as prop.
For example, your code might look like this:
import React from 'react';
import Two from './Two' // I am assuming One.js and Two.js are in same folder.
class One extends React.Component {
constructor(props) {
super(props);
this.state = {
data: 'hi'
}
}
render() {
return (
<div>
<div>{this.state.data}</div>
<Two value={this.state.data} />
</div>
);
}
}
export default One;
And then in the Two.js you can access the value as below:
import React from 'react';
class Two extends React.Component {
render() {
return (
<div>{this.props.value}</div>
);
}
}
export default Two;
Now, let's say, you are using your component One in App or anywhere. Whenever you will use <One/> you will get following in the browser:
hi
hi
You must call this 'Two' component into 'One' like this
One Component:
render() {
return (
<Two myProp={this.state.data} />
)
}
You can call this whatever u wish (myProp)
And read this in 'Two' component:
render() {
return (
<div>Received data from parent Component: {this.props.myProp}</div>
)
}
Before you call 'Two' component into 'One' you must import that file
import Two from './path/to/component';
Just add the following code in One component render method and pass the data as props which is read-only
import React from 'react';
import Two from '/components/Two'
class One extends React.Component {
constructor(props) {
super(props);
this.state = {
data: 'hi'
}
}
render() {
return (
<div prop={this.state.data}>{this.state.data}</div>
<Two data={this.state.data} />
);
}
}
export default One;
Then In component Two to access data add following code
import React from 'react';
class Two extends React.Component {
constructor(props){
super(props)
}
render() {
return (
<div>{this.props.data}</div>
);
}
}
export default Two;
Props will hold the object transferred from parent element
One.js
import React from 'react';
import Two from './two'
class One extends React.Component {
constructor(props) {
super(props);
this.state = {
data: 'hi'
}
}
render() {
return (
<div>{this.state.data}
<Two dto={this.state} /></div>
);
}
}
export default One;
Two.Js
import React from 'react';
class Two extends React.Component {
render() {
return (
<div>Component Two data: {this.props.dto.data}</div>
);
}
}
export default Two;
I am getting ./src/App.js Line 27: 'Items' is not defined react/jsx-no-undef
while trying to pass state to a another component
import React, { Component } from 'react';
import axios from 'axios'
class App extends Component {
// Added this:
constructor(props) {
super(props);
// Assign state itself, and a default value for items
this.state = {
items: []
};
}
componentWillMount() {
axios.get('https://api.opendota.com/api/proMatches').then(res => {
this.setState({ items: res.data });
});
}
render() {
return (
<div className="app">
<Items items={this.state.items} />
</div></blink></blink>
);
}
}
export default App;
You are not trying to use a component called Items without importing it first:
<Items items={this.state.items} />
Every component that you use must be imported first:
import { Items } from "DIRECTORY"
Errors:- (1) import Items component (2) use componentDidMount() instead of componentWillMount() (3) use ternary operator in JSX this.state.items.length > 0 for displaying items after getting response
import React, { Component } from 'react';
import axios from 'axios';
import Items from './Items';
class App extends Component {
// Added this:
constructor(props) {
super(props);
// Assign state itself, and a default value for items
this.state = {
items: []
};
}
componentDidMount() {
axios.get('https://api.opendota.com/api/proMatches').then(res => {
this.setState({ items: res.data });
});
}
render() {
return (
<div className="app">
{
this.state.items.length > 0 ?
<Items items={this.state.items} /> : null
}
</div></blink></blink>
);
}
}
export default App;
App is top component and Items is child component.To use any child component or pass any kind props or state ,it has to be imported first .
There can be another issue to it since you are using state and if the child component Items is rerendered due to any change ,then state of your APP component will also reset.
I have following code which is rendering the React app.
import React from 'react';
import ReactDOM from 'react-dom';
import SearchBar from './components/search_bar';
import YTSearch from 'youtube-api-search';
import VideoList from './components/video_list'
const API_KEY = 'AIzaSyCF7K58Xwpr7m5C0yGy8Bck02iQ0fJ2yuI';
class App extends React.Component {
constructor(props){
super(props);
this.state = {videos: []};
this.YTSearch = this.YTSearch.bind(this);
}
YTSearch({key: API_KEY, term: BMW}, (videos => {
this.setState({ videos });
});
);
render() {
return (
<div>
<SearchBar />
<VideoList videos={ this.state.videos }/>
</div>
);
}
}
ReactDOM.render(<App />, document.querySelector('.container'));
Also I think I have some syntax problem with using the setState function.
Class body is for defining functions and variables but you are calling the function YTSearch inside class body, which is giving syntax error. If you want to call the function then either call it inside constructor or inside any other function like componentDidMount etc
constructor(props){
super(props);
this.state = {videos: []};
}
componentDidMount(){
// Call it here inside componentDidMount or any other function
YTSearch({key: API_KEY, term: BMW}, (videos => {
this.setState({ videos });
}));
}
Your destructured setState is fine, you have a bracket (open which needs to be closed or either way you can remove it as there is only one argument in your arrow function.
Your specific issue isn't made clear in your question but from looking at your code I assume your YTSearch is never firing and therefore your state never gets set with a list of videos.
If you are trying to create a method to pass to the search bar that triggers a search perhaps try something like this. I hope this helps!
import React from 'react';
import ReactDOM from 'react-dom';
import SearchBar from './components/search_bar';
import YTSearch from 'youtube-api-search';
import VideoList from './components/video_list';
const API_KEY = 'AIzaSyCF7K58Xwpr7m5C0yGy8Bck02iQ0fJ2yuI';
class App extends React.Component {
constructor(props) {
super(props);
this.state = { videos: [] };
this.search = this.search.bind(this);
}
search(phrase) {
YTSearch({ key: API_KEY, term: phrase }, videos => {
this.setState({ videos });
});
}
render() {
return (
<div>
<SearchBar onSearch={this.search}/>
<VideoList videos={this.state.videos} />
</div>
);
}
}
ReactDOM.render(<App />, document.querySelector('.container'));
could you please suggest how to set initial value in react ?
here is my code
http://codepen.io/naveennsit/pen/mPYzdw
class App extends React.Component{
getInitialState(){
return {data: 'test'};
}
render(){
return <div>hello {this.state.data}</div>
}
}
React.render(<App/>,document.getElementById('app'))
See this post from the React blog.
You set it in the constructor.
import {Component} from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {data: 'test'};
}
render() { ... }
}
Also, I notice you're using React.render which is no longer a thing.
import {render} from 'react-dom'
// ...
render(<App/>, document.getElementyById('app'));
I'm trying to use ES6 classes inside of React, and want all my components to inherit certain methods, however as soon as I try to extend a component which extends the React.Component class, the componentDidMount method doesn't trigger and hence nothing gets rendered. The code I'm using:
BaseComponent.jsx
import React from 'react';
class BaseComponent extends React.Component {
constructor() {
super();
console.log('BaseComponent constructor');
}
render() {
return (
<div>Hello, Im the base component</div>
);
}
}
export default BaseComponent;
ExampleComponent.jsx
import BaseComponent from './BaseComponent';
class ExampleComponent extends BaseComponent {
constructor(props) {
super(props);
}
componentDidMount() {
console.log('exampleComponent mounted');
}
render() {
return (
<div>Hello, Im the example component</div>
);
}
}
export default ExampleComponent;
App.jsx
import React from 'react';
React.render(<ExampleComponent />, document.body);
I'm using React 0.13.3, and using babelify 6.1.2 to transpile.
The string 'exampleComponent mounted' never gets logged to console, and nothing is rendered. Any ideas what I'm doing wrong?
I'm not sure about the approach, but this code also works:
export default class Service extends BaseComponent {
componentDidMount(...args) {
super.componentDidMount.apply(this, args);
}
}
UPD: this is considered to be a bad practice though:
a) https://medium.com/#dan_abramov/how-to-use-classes-and-sleep-at-night-9af8de78ccb4
b) https://medium.com/#dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750
I think, the problem is that you cannot create deeper class-structures for react components. Also, you shouldn't have to need it. On your example the BaseComponent is useless anyway.
Try this instead:
import React from 'react';
export default class ExampleComponent extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log('exampleComponent mounted');
}
render() {
return (
<div>Hello, Im the example component</div>
);
}
}
If you want to create 'BaseComponents', you could implement them as mixins or simply as 'sub components'.
This could look like this:
import React from 'react';
import BaseComponent from './BaseComponent';
export default class ExampleComponent extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log('exampleComponent mounted');
}
render() {
return (
<div>
<div>Hello, Im the example component</div>
<BaseComponent />
</div>
);
}
}
EDIT: Also possible:
import React from 'react';
import BaseComponent from './BaseComponent';
export default class ExampleComponent extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
console.log('exampleComponent mounted');
}
render() {
return (
<BaseComponent
<div>Hello, Im the example component</div>
</BaseComponent>
);
}
}
// BaseComponent.js
render() {
return {
<div>
<div>Hello, Im the base component</div>
{this.props.children}
</div>
}
}
EDIT #2: Above code works fine with es5/jsx syntax.
DEMO