Ok so I am trying to understand React Hooks and how to update
my code to grab the JSON from the source below and show the data. I'm clear on importing the hook and initializing it with useState(0) but my code fails when I try to re-factor within my fetch statement. Any/all help would be greatly appreciated...see below.
// import React, { Component } from 'react';
import React, { useState } from 'react';
import Feeder from './Feeder';
import Error from './Error';
// class NewsFeeder extends Component {
// constructor(props) {
// super(props);
// this.state = {
// news: [],
// error: false,
// };
// }
const [hideNews,showNews] = useState(0);
componentDidMount() {
const url = `https://newsfeed.com`;
fetch(url)
.then((response) => {
return response.json();
})
.then((data) => {
this.setState({
news: data.articles
})
})
.catch((error) => {
this.setState({
error: true
})
});
}
renderItems() {
if (!this.state.error) {
return this.state.news.map((item) => (
<FeedPrime key={item.url} item={item} />
));
} else {
return <Error />
}
}
render() {
return (
<div className="row">
{this.renderItems()}
</div>
);
}
}
export default NewsFeeder;
React hooks are created for functional components and are not ment to be used in class components.
Here is a table of the functionality and the way to achive it using classes and functions with hooks.
component type
state
fetch
class
store the state in this.state that you only assign once in the constructor, use this.setState to modify the state
do your fetch logic in componentDidMount
function
create a pair of [example, setExample] with useState
do fetch in useEffect hook
Using fetch with hooks: (edited version of this):
import React, { useState, useEffect } from 'react';
function App() {
const [data, setData] = useState({ hits: [] });
useEffect(async () => {
const result = await fetch('https://hn.algolia.com/api/v1/search?query=redux').then(response => response.json());
setData(result);
});
let items = data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
));
return (
<ul>
{items}
</ul>
);
}
export default App;
Related
My nextjs app uses getInitialProps to fetch data from a streaming API, and then checks every second thereafter for updates. When the API changes (when the current track ends and a new one begins) I would like for the trackName to change on screen. What I have here works so long as I log the output to console, but for some reason the UI will not update.
I believe that trackName is passed down to the child as a prop? And then the child is trying to set the state in componentDidMount? My understanding of this feels shaky.
This is my _app.js:
import React, { useState } from 'react'
import Player from '../components/Player'
function MyApp({ Component, pageProps, tracks }) {
const url = "https://kchungradio.out.airtime.pro/kchungradio_a"
const trackName = tracks.current.name
return (
<>
<Player
url={url}
trackName={trackName}
/>
<Component {...pageProps} />
</>
)
}
MyApp.getInitialProps = async (appContext) => {
let res = await fetch("https://kchungradio.airtime.pro/api/live-info-v2")
let data = await res.json()
return { tracks: data.tracks }
}
export default MyApp
And this is my Player:
import { Component } from 'react'
import React from 'react'
import ReactPlayer from 'react-player'
export default class Player extends React.Component {
constructor(props) {
super(props)
}
componentDidMount() {
setInterval(() => {
fetch("https://kchungradio.airtime.pro/api/live-info-v2", {
method: "GET"
})
.then(response => {
if (!response.ok) {
return Promise.reject(response)
}
return response.json()
})
.then(data => {
this.updateCurrentTrack(data.tracks.current.name)
})
.catch(error => {
if (typeof error.json === "function") {
error.json().then(jsonError => {
console.log(jsonError)
}).catch(genericError => {
console.log("Generic error from API")
console.log(error.statusText)
})
} else {
console.log("Fetch error")
console.log(error)
}
})
}, 1000)
}
updateCurrentTrack = (name) => {
this.setState({
trackName: name
})
console.log(name)
}
render() {
const { url, trackName } = this.props
return (
<div class="player">
<ReactPlayer
url={url}
/>
<div>{trackName}</div>
</div>
)
}
}
this.props.trackName is not the same than this.state.trackName. You are setting a state element that is never declared in the contructor and using the trackName froms this.props which is only received once from it's parent component.
try this in the constructor:
constructor(props) {
super(props)
this.state = {
trackName: '',
}
}
and in your jsx
render() {
const { url, trackName } = this.props
const { trackName: stateTrackName } = this.state // rename since trackName has already been declared
return (
<div class="player">
<ReactPlayer
url={url}
/>
<div>{stateTrackName || trackName}</div>
// or whats the same
// <div>{this.state.trackName || this.props.trackName}</div>
</div>
)
}
My idea is that please use useState and useEffect.
In my next.js applications:
I import useEffect and useState from react.
Create 2 constact in useState.
Create a useEffect that and in the array of useEffect, set first const.
In the useEffect, change amount of second const.
This code is a dashboard page of one of my apps.
// IMPORT CTRL
import DashboardCtrl from "../../components/dashboard/ctrl";
// IMPORT DETAILS COMPONENTS
import UserInfo from "../../components/dashboard/userInfo";
import NewProjects from "../../components/dashboard/newProjects";
import { useState,useEffect } from "react";
const Dashboard = () => {
const [content,setcontent]=useState("UserInfo");
const [details,setdetails]=useState(<UserInfo/>);
useEffect(()=>{
if (content=="UserInfo") {
setdetails(<UserInfo/>);
}else if(content=="NewProjects"){
setdetails(<NewProjects/>);
}
},[content])
return (
<main>
<div className=" container mx-auto flex justify-between items-start my-8">
<div className=" w-1/4">
{details}
</div>
<div className=" w-1/4">
<DashboardCtrl setcontent={setcontent}/>
</div>
</div>
</main>
);
}
export default Dashboard;
I'm trying to update state in React.js using an API call, as I need to show some of the data to the end user.
The api call works through localhost:5001 and is stored in Firebased functions.
import React, { Component } from 'react'
import './Table.css';
class Table extends Component {
constructor (props)
{
super(props);
this.state = {
stocks: []
};
}
componentDidMount() {
fetch('localhost:5001') // Removed for stackoverflow //
.then((response) => response.json())
.then(stockList => {
this.setState =
({ stocks: stockList });
});
}
render() {
return (
<div className='table'>
<h1 id='title'>Companies</h1>
{this.state.stocks.map(stocks => <h2 key={stocks.symbol}> {stocks.companyName}</h2>)}
</div>
)
}
}
export default Table;
Here is a snippet of the API call:
{"symbol":"AAPL","companyName":"Apple Inc"}
setState is a function, so you should call it, rather that assign values to it:
this.setState({ stocks: stockList });
Please suggest to how to write the constructor in functional component using react js...as I'm planning to convert class component to functional component....could anyone help that
import React, { Component } from "react";
class Example extends Component {
constructor(props) {
super(props);
this.state = {
users: []
};
}
componentDidMount() {
axios
.get("https://www.example.com/users/id")
.then(response => {
this.setState({ descriptions: response.data });
// console.log(response.data)
})
.catch(error => {
console.log(error);
});
}
render() {
const { users } = this.state;
return <div>Data</div>;
}
}
export default Example;
In order to use state, or lifecycle method in functional components you should use React Hooks
import React, { useState, useEffect } from 'react';
const Example =() => {
const [users, setUsers] = useState([])
useEffect(()=> {
axios.get("https://www.example.com/users/id")
.then(response => {
// use setState hook here
// console.log(response.data)
})
.catch(error => {
console.log(error)
})
}, [])
return (
<div>
Data
</div>
)
}
export default Example
I want to know whats wrong with my code every-time i got this MSG "Cannot read property 'params' of undefined" I want to pass a props from page to another, I've fetch multi API and from the second API i want to get some images to pass it on the other view. The first API working fine at ProfileHeader.JS but the second one with ProfileTabs.JS Iam facing some problems with it.
I'am not sure where is my problem - "sorry for my poor English"
My first view:
ProfileLanding.JS
import React, { useState, useEffect } from 'react'
import ProfileHeader from './ProfileHeader';
import ProfileTabs from './ProfileTabs';
function ProfileLanding({ match }) {
useEffect(() => {
fetchUser();
console.log(match);
}, []);
const [user, setUser] = useState({
image: {}
});
const [usergallery, setUsergallery] = useState({
image: {}
});
const fetchUser = async () => {
let [fetchUser, fetchUsergallery] = await Promise.all([
fetch(
`http://arabcdb.com/backstage/login/teamapibyid/${match.params.id}`
),
fetch(
`https://arabcdb.com/backstage/login/mediateamapiid/${match.params.id}`
)
]);
const userr = await fetchUser.json();
setUser(userr);
const usergalleryr = await fetchUsergallery.json();
setUsergallery(usergalleryr);
};
return(
<section className="col-md-9">
<ProfileHeader user={user} />
<ProfileTabs usergallery={usergallery} />
</section>
)
}
export default ProfileLanding;
and this is my second view:
ProfileTabs.JS
import React, { Component } from "react";
import ReactDOM from "react-dom";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useParams
} from "react-router-dom";
import './ProfileTabs.css'
class ProfileTabs extends Component{
constructor(props) {
super();
this.state = { data: [] };
console.log(props)
}
componentDidMount() {
const test = this.props.match.params.id;
fetch(`http://arabcdb.com/backstage/login/mediateamapiid/${test}`)
.then(res => res.json())
.then(json => this.setState({ data: json }));
}
render() {
return (
<div>
<div className="gallery" id="gallery">
{
this.state.data.map(item => (
<div className="mb-3 pics animation all 2" key={item.id}><img className="img-fluid" src={"http://arabcdb.com/backstage/uploads/" + item.image} alt="Card cap" /></div>
))
}
</div>
</div>
);
}
}
export default ProfileTabs;
View Error MSG
That's because you don't actually have the match prop.
In your ProfileTabs.js file since you are using a class component you should wrap it in the withRouter HOC. Or if you prefer to use function components you can then use the useparams hook.
You can also pass the prop down from the ProfileLanding.js component.
Use the one that is easier for you.
I'm using react-lifecycle-component in my react app, and incurred in this situation where I need the componentDidMount callback to load some data from the backend. To know what to load I need the props, and I can't find a way to retrieve them.
here's my container component:
import { connectWithLifecycle } from "react-lifecycle-component";
import inspect from "../../../libs/inspect";
import fetchItem from "../actions/itemActions";
import ItemDetails from "../components/ItemDetails";
const componentDidMount = () => {
return fetchItem(props.match.params.number);
};
// Which part of the Redux global state does our component want to receive as props?
const mapStateToProps = (state, props) => {
return {
item: state.item,
user_location: state.user_location
};
};
// const actions = Object.assign(locationActions, lifecycleMethods);
export default connectWithLifecycle(mapStateToProps, { componentDidMount })(
ItemDetails
);
Any clues?
thanks.
import React, { Component } from 'react'
import { connect } from 'react-redux'
import fetchItem from '../actions/itemActions'
class Container extends Component {
state = {
items: []
}
componentDidMount() {
const { match } = this.props
fetchItem(match.params.number)
// if your fetchItem returns a promise
.then(response => this.setState({items: response.items}))
}
render() {
const { items } = this.state
return (
<div>
{ items.length === 0 ? <h2>Loading Items</h2> :
items.map((item, i) => (
<ul key={i}>item</ul>
))
}
</div>
)
}
const mapStateToProps = (state, props) => {
return {
item: state.item,
user_location: state.user_location
}
}
export default connect(mapStateToProps)(Container)
Though I don't see where you are using the props you take from your Redux store...