React Components inside fragment not loading - reactjs

I'm using react 16.2.0 and react-dom 16.2.0. Following is the code I have.
import React, { Fragment } from 'react';
import BodyComponent from './BodyComponent';
import * as HeaderComponents from './HeaderComponent';
class TablePage extends React.Component {
constructor(props) {
super(props);
}
render() {
const MyHeader = (props) => {
const Header = HeaderComponents.TableHeader;
return <Header status={props.status}/>;
};
let pageContent = null;
pageContent = (
<ul className="list-table" role="table" aria-label={MessageConstants.ASSIGNMENT_ITEMS_TABLE_CAPTION_MESSAGE}>
<MyHeader status={status}/>
{
items.map((item, i) => {
return <TableBody dataSet={item} key={i}/>;
})
}
</ul>
);
return (pageContent);
}
}
class TableBody extends React.Component {
constructor(props) {
super(props);
}
render() {
const {dataSet} = this.props;
const BodyHeader = (props) => {
const Header = HeaderComponents.BodyHeader;
return <Header index={this.props.index}/>;
};
return (
<Fragment>
<BodyHeader index={this.props.index}/>
<BodyComponent itemList={dataSet.content}/>
</Fragment>
);
}
}
export default TablePage;
My problem is, the components I'm returning inside are not rendering. I don't get any errors in the console as well.
I tried rendering simple html code such as
<Fragment>
<p>foo</p>
<p>bar</p>
</Fragment>
But the issue remains. Can someone please help me with this.

Related

Child component not triggering rendering when parent injects props with differnt values

Here are my components:
App component:
import logo from './logo.svg';
import {Component} from 'react';
import './App.css';
import {MonsterCardList} from './components/monster-list/monster-card-list.component'
import {Search} from './components/search/search.component'
class App extends Component
{
constructor()
{
super();
this.state = {searchText:""}
}
render()
{
console.log("repainting App component");
return (
<div className="App">
<main>
<h1 className="app-title">Monster List</h1>
<Search callback={this._searchChanged}></Search>
<MonsterCardList filter={this.state.searchText}></MonsterCardList>
</main>
</div>
);
}
_searchChanged(newText)
{
console.log("Setting state. new text: "+newText);
this.setState({searchText:newText}, () => console.log(this.state));
}
}
export default App;
Card List component:
export class MonsterCardList extends Component
{
constructor(props)
{
super(props);
this.state = {data:[]};
}
componentDidMount()
{
console.log("Component mounted");
this._loadData();
}
_loadData(monsterCardCount)
{
fetch("https://jsonplaceholder.typicode.com/users", {
method: 'GET',
}).then( response =>{
if(response.ok)
{
console.log(response.status);
response.json().then(data => {
let convertedData = data.map( ( el, index) => {
return {url:`https://robohash.org/${index}.png?size=100x100`, name:el.name, email:el.email}
});
console.log(convertedData);
this.setState({data:convertedData});
});
}
else
console.log("Error: "+response.status+" -> "+response.statusText);
/*let data = response.json().value;
*/
}).catch(e => {
console.log("Error: "+e);
});
}
render()
{
console.log("filter:" + this.props.filter);
return (
<div className="monster-card-list">
{this.state.data.map((element,index) => {
if(!this.props.filter || element.email.includes(this.props.filter))
return <MonsterCard cardData={element} key={index}></MonsterCard>;
})}
</div>
);
}
}
Card component:
import {Component} from "react"
import './monster-card.component.css'
export class MonsterCard extends Component
{
constructor(props)
{
super(props);
}
render()
{
return (
<div className="monster-card">
<img className="monster-card-img" src={this.props.cardData.url}></img>
<h3 className="monster-card-name">{this.props.cardData.name}</h3>
<h3 className="monster-card-email">{this.props.cardData.email}</h3>
</div>
);
}
}
Search component:
import {Component} from "react"
export class Search extends Component
{
_searchChangedCallback = null;
constructor(props)
{
super();
this._searchChangedCallback = props.callback;
}
render()
{
return (
<input type="search" onChange={e=>this._searchChangedCallback(e.target.value)} placeholder="Search monsters"></input>
);
}
}
The problem is that I see how the text typed in the input flows to the App component correctly and the callback is called but, when the state is changed in the _searchChanged, the MonsterCardList seems not to re-render.
I saw you are using state filter in MonsterCardList component: filter:this.props.searchText.But you only pass a prop filter (filter={this.state.searchText}) in this component. So props searchTextis undefined.
I saw you don't need to use state filter. Replace this.state.filter by this.props.filter
_loadData will get called only once when the component is mounted for the first time in below code,
componentDidMount()
{
console.log("Component mounted");
this._loadData();
}
when you set state inside the constructor means it also sets this.state.filter for once. And state does not change when searchText props change and due to that no rerendering.
constructor(props)
{
super(props);
this.state = {data:[], filter:this.props.searchText};
}
If you need to rerender when props changes, use componentDidUpdate lifecycle hook
componentDidUpdate(prevProps)
{
if (this.props.searchText !== prevProps.searchText)
{
this._loadData();
}
}
Well, in the end I found what was happening. It wasn't a react related problem but a javascript one and it was related to this not been bound to App class inside the _searchChanged function.
I we bind it like this in the constructor:
this._searchChanged = this._searchChanged.bind(this);
or we just use and arrow function:
_searchChanged = (newText) =>
{
console.log("Setting state. new text: "+newText);
this.setState({filter:newText}, () => console.log(this.state));
}
Everything works as expected.

Pass original component's function to react HOC

I have created react HOC component as below.
const UpdatedComponent = (OriginalComponent) => {
class NewComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
counter:0
}
}
componentDidMount(){
}
incrementCount = () => {
this.setState(prevState => {
return {counter:prevState.counter+1}
})
}
render(){
return <OriginalComponent
incrementCount={this.incrementCount}
count={this.state.counter}
/>
}
}
return NewComponent
}
export default UpdatedComponent
and I am using that component in the below example
class HoverCounter extends Component {
componentDidMount(){
}
handleMessages = () => {
// need to do somthing
}
render() {
const {incrementCount, count} = this.props
return (
<div onMouseOver={incrementCount}>
Hoverd {count} times
</div>
)
}
}
export default UpdatedComponent(HoverCounter)
I want to know that is it possible to pass
handleMessages()
function to HOC?
like this
export default UpdatedComponent(HoverCounter,handleMessages)
I have no idea how to pass the original component function or props to HOC.
you could get everyThing in your Hoc like this :
const UpdatedComponent = (OriginalComponent , func) => {
componentDidMount(){
func()
}
in HoverCounter also you could add this changes:
static handleMessages(){
// need to do something
}
export default UpdatedComponent(HoverCounter , HoverCounter.handleMessages)

ReactJS -- Unable to find latest title from an api causing error

I have a Landing component and a NewsLatest component. I am hitting on an api and trying to find the article with the latest timestamp but iam unable to get it done in reactJS.I checked the js code its working fine but in react it is not rendering. Kindly suggest something.
import React, { Component } from 'react'
import NewsSearch from '../NewsSearch/NewsSearch';
import NewsLatest from '../NewsLatest/NewsLatest';
import './Landing.css';
import axios from 'axios';
class Landing extends Component {
state={
newsList: []
}
componentDidMount(){
axios.get(`https://api.nytimes.com/svc/topstories/v2/home.json?api-key=7cK9FpOnC3zgoboP2CPGR3FcznEaYCJv`)
.then(res=> {
this.setState({newsList: res.data.results});
});
}
render() {
// console.log(this.state.newsList);
return (
<div className="landing text-center text-white">
<h1>News Portal</h1>
<div className="news-search">
<NewsSearch />
</div>
<div className="news-latest">
<NewsLatest newsList={this.state.newsList}/>
</div>
</div>
)
}
}
export default Landing;
import React, { Component } from 'react';
// import PropTypes from 'prop-types';
class NewsLatest extends Component {
constructor(props){
super(props);
this.state = {
newsTitle:'',
abstract:'',
newsUrl:'',
}
// this.newsLatest = this.newsLatest.bind(this);
}
newsLatest = (e)=>{
// e.preventDefault();
const {newsList} = this.props;
let maxTime = newsList.map(function(o) {
return new Date(o.updated_date);
});
let maximumValue = Math.max(...maxTime);
let latestnews = newsList.filter(function (el) {
return maximumValue === new Date(el.updated_date).getTime();
})[0];
if(latestnews){
this.setState({newsTitle: latestnews.title});
return (<h4>{this.state.newsTitle}</h4>);
}
}
newsTitle = () => (
this.props.newsList.map(item => (<h2 key={item.title}>{item.title}</h2>))
)
render() {
console.log(this.props.newsList);
return (
<div>
<h2>News Latest....</h2>
{this.newsLatest()}
</div>
);
}
}
export default NewsLatest;
There is some issue in rendering in NewsLatest component. KIndly suggest something.
Try this:
You must probably be getting a maximum depth error, use a lifecycle method instead like componentDidUpdate. Update your component state only if the previous props are different from the newer ones.
Read more here: https://reactjs.org/docs/react-component.html
import React, { Component } from "react";
// import PropTypes from 'prop-types';
class NewsLatest extends Component {
constructor(props) {
super(props);
this.state = {
newsTitle: "",
abstract: "",
newsUrl: ""
};
// this.newsLatest = this.newsLatest.bind(this);
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.newsList !== this.props.newsList) {
const { newsList } = this.props;
let maxTime = newsList.map(function(o) {
return new Date(o.updated_date);
});
let maximumValue = Math.max(...maxTime);
let latestnews = newsList.filter(function(el) {
return maximumValue === new Date(el.updated_date).getTime();
})[0];
this.setState({ newsTitle: latestnews.title });
}
}
// newsLatest = e => {
// // e.preventDefault();
// const { newsList } = this.props;
// let maxTime = newsList.map(function(o) {
// return new Date(o.updated_date);
// });
// let maximumValue = Math.max(...maxTime);
// let latestnews = newsList.filter(function(el) {
// return maximumValue === new Date(el.updated_date).getTime();
// })[0];
// console.log(latestnews)
// if (latestnews && latestnews.hasOwnProperty('length') && latestnews.length>0) {
// return <h4>{this.state.newsTitle}</h4>;
// }
// };
newsTitle = () =>
this.props.newsList.map(item => <h2 key={item.title}>{item.title}</h2>);
render() {
console.log(this.props.newsList);
return (
<div>
<h2>News Latest....</h2>
<h4>{this.state.newsTitle}</h4>
</div>
);
}
}
export default NewsLatest;
Also, a sandbox: https://codesandbox.io/s/hungry-frog-z37y0?fontsize=14

Converting functional component to class component

I have one functional component, but as I need to use now state and more complex logic, I would like to convert it to class component.
But I don't know exactly how to get it working:
My functional component:
import React from 'react';
const FileList = (props) => {
const items = props.items.map((item) => {
return <p key={item.reqId} > { item.name }</ p>
});
return <div>{items}</div>
}
And I tried to do that:
export default class FileL extends React.Component {
constructor(props) {
super(props)
}
render() {
const { items } = this.props;
items = props.items.map((item) => {
return <p key={item.reqId} > {item.name}</ p>
});
return (
<div>{items}</div>
);
}
}
But this is not working.It says "items" is read-only.
I would like to keep the same functionality.
Any ideas?
In your render function
render() {
const { items } = this.props;
items = props.items.map((item) => {
return <p key={item.reqId} > {item.name}</ p>
});
return (
<div>{items}</div>
);
}
items is const so you can't override it. This has nothing to do with React. And you shouldn't reassign a props element, even if its defined with let. You might use the following:
render() {
const { items } = this.props;
return (
<div>
{
items.map((item) => <p key={item.reqId} > {item.name}</ p>)
}
</div>
);
}
You can try this,
export default class FileL extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
{
this.props.items.map((item) => {
return <p key={item.reqId} > {item.name}</ p>
})
}
</div>
);
}
}
Actually you don't need to convert your component to class based component, as React 16.8 comes with Hooks. Using Hooks you can do whatever you can do with class based component. They let you use state and other React features without writing a class.

Unable to find an error

i know it's a minor and maybe a fool question but i'm stuck for about an hour at an error which i cant see. This is my code:
const ModalRoot = ({ modalType, modalProps, locale }) => {
if (!modalType) {
return <span />;
}
return (
<IntlProvider
locale={locale}
key={locale}
messages={messagesFor(locale)}
>
<div className="backdrop">
{renderAppropriateModal(modalType, modalProps)}
</div>
</IntlProvider>
);
};
The console shows an error in the if saying unexpected token. Why is this happening??
This can be your error...
check this samples.
Wrong place to declare.
import React from 'react';
class YOURCLASS extends React.Component {
constructor(props) {
super(props);
}
//do not place this ModalRoot here
const ModalRoot = ({ modalType, modalProps, locale }) => {
//contents
}
render(){
return(
<div>{yourContent}</div>
);
}
}
Right place to declare
import React from 'react';
//Place it here outside the class YOURCLASS
const ModalRoot = ({ modalType, modalProps, locale }) => {
//contents
}
class YOURCLASS extends React.Component {
constructor(props) {
super(props);
}
render(){
return(
<div>{yourContent}</div>
);
}
}
if you still intends to do it inside class... better use function instead...
import React from 'react';
class YOURCLASS extends React.Component {
constructor(props) {
super(props);
}
//function type ModalRoot
ModalRoot(modalType, modalProps, locale){
//contents
return <IntlProvider />;
}
render(){
const {modalType, modalProps, locale} = this.props;
let yourContent = this.ModalRoot(modalType, modalProps, locale);
return(
<div>{yourContent}</div>
);
}
}
hope it helps...

Resources