Problem with loading JSON file in React Router - javascript

I try to get only the name's region in this API link but it shows me errors in the properties of the setState. Syntax problem or something else?
By the way: Why I use this case, map function? For future purposes.
Thanks!
App Js :
import React from 'react';
import './App.css';
import Region from './region';
import {BrowserRouter,Switch,Route} from "react-router-dom";
function App() {
return (
<div className="App">
<BrowserRouter>
<Switch>
<Route exact path = "/" component={Region}/>
</Switch>
</BrowserRouter>
</div>
);
}
export default App;
the component:
import React, { Component } from "react";
class Region extends Component {
constructor (props) {
super (props)
this.state = {
items:[],
isLoad:false
}
}
ComponentDidMount () {
fetch("https://restcountries.eu/rest/v2/region/europe").then(res=>res.json()).then(JSON=> {
this.setState ({
isLoad = true,
items = JSON,
})
})
}
render () {
let {isLoad,items} = this.state;
if(!isLoad) {
return <div>Loading...</div>
}
else {
return <div>
<ul>
{items.map(items=>(
<li key={items.name}> </li>
))}
</ul>
</div>
}
}
}
export default Region;
json file: https://restcountries.eu/rest/v2/region/europe

The reason behind .map() is you get an opportunity to manipulate your array elements by accessing each elements and returning a different way, structure. In React case it helps to render proper JSX elements for render() method. Suggested read Lists and Keys from React's official documentation.
Read from Array.prototype.map() documentation:
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
First issue is wrongly passed properties to setState(), please note that I'm using : instead of =. Try to change as the following:
this.setState({
isLoad: true,
items: JSON,
});
Additionally you can try the following - you had the same name for current element as the array itself - it just better to have different name:
return <div>
<ul>
{items && items.map(e => <li key={e.name}> {e.name} </li>)}
</ul>
</div>
I hope that helps!

Related

Problem when pass data in ReactJS with props and state

I have the problem when I try to pass the props through the function component .In parent component I have a state of currentRow with return an array with object inside, and I pass it to child component. It return a new object with an array inside it. What can I do to avoid it and receive exact my currentRow array.
there is example of the way I do it
Parent component
import React, { useState } from "react";
import ToolBar from "./Toolbar";
function Manage() {
const [currentRow, setCurrentRow] = useState();
console.log("from manage", currentRow);
return (
<div>
<ToolBar currentRow={currentRow} />
</div>
);
}
export default Manage;
Child Componet
import React from 'react'
function ToolBar(currentRow) {
console.log("from toolbar", currentRow);
return(
<div></div>
);
}
export default ToolBar
And this is my Log
enter image description here
Try accessing it like below:
import React from 'react'
function ToolBar({currentRow}) {
console.log("from toolbar", currentRow);
return(
<div></div>
);
}
export default ToolBar
A React component's props is always an object. The reason for this is that otherwise it would be impossible to access the properties of a component which received multiple props.
example:
<SomeComponent prop1={prop1} prop2={prop2} />
---
const SomeComponent = (props) => {
console.log(props.prop1);
console.log(props.prop2);
}
So in order to resolve your issue, you could destructure the props object in your ToolBar component like this:
const ToolBar = ({ currentRows }) => {
...
}
Just keep in mind that a component will always receive its props as an object. There is no way to change that as of right now.

React: Problem in dynamic nested routing. How to solve this error?

I am getting the following error while trying to implement dynamic routing in React JS.
The required files are:
Assignment.js
import React, { Component } from 'react';
import Users from './containers/Users/Users';
import Courses from './containers/Courses/Courses';
import {Route, Link, Switch, Redirect} from 'react-router-dom';
import Course from './containers/Course/Course';
class Assignment extends Component{
render(){
return(
<div>
<ul>
<li><Link to ="/Users"> Users </Link></li>
<li><Link to ="/Courses"> Courses </Link></li>
</ul>
<Switch>
<Route path ="/Users" component = {Users}/>
<Route path ="/Courses" exact component = {Courses}/>
</Switch>
</div>
)
}
};
export default Assignment;
Courses.js
import React, { Component } from 'react';
import {Link, Route} from 'react-router-dom';
import './Courses.css';
import Course from '../Course/Course';
class Courses extends Component {
state = {
courses: [
{ id: 1, title: 'Angular - The Complete Guide' },
{ id: 2, title: 'Vue - The Complete Guide' },
{ id: 3, title: 'PWA - The Complete Guide' }
]
}
render () {
return (
<div>
<h1>Amazing Udemy Courses</h1>
<section className="Courses">
{
this.state.courses.map( course => {
return (<Link key ={course.id} to = {this.props.match.url + '/' + course.id + '/' + course.title}>
<Course className = "Course" name = {course.title} no = {course.id} />
</Link>);
} )
}
<Route path = "/Courses/:id/:name" exact component = {Course} />
</section>
</div>
);
}
}
export default Courses;
Course.js
import React, { Component } from 'react';
class Course extends Component {
render () {
return (
<div>
<h1>{this.props.match.params.name}</h1>
<p>{this.props.match.params.id}_</p>
</div>
);
}
}
export default Course;
Why am I getting this error? Can anyone fix this? I am also finding it difficult to following dynamic routing.
PS. I am getting the error at /Courses url only not at the base url.
Have you tried withRouter?
import { withRouter } from 'react-router-dom';
console.log(props.match.params);
then export the component like:
export default withRouter(TestComponent);
Problems
The props such as params are only passed down to the top-level component which is rendered by a Route. When you are rendering the list of individual Course components inside your Course component, the Courses gets this.props.params but each Course does not. You can pass them down manually:
<Course {...this.props} className="Course" name={course.title} no={course.id} />
The above passes all props, while the below passes just the params prop.
<Course params={this.props.params} className="Course" name={course.title} no={course.id} />
This resolves your error, but it is not at all doing what you want it to be doing. The match is for the current URL, so this.props.match.params.name and this.props.match.params.id are both empty values when we are on the /Courses page. Meanwhile, the props className, name, and no which you set on the Course are all unused.
Additionally, the Route to "/Courses/:id/:name" which you have put inside of Courses should really be on the top level of the app alongside the main "/Courses" Route. Ideally it should be listed before the courses homepage route because you want to match to more specific paths before broader ones, but it won't present any conflicts with exact either way.
There is a lot wrong here and I recommend that you read up on the fundamentals of react-router and writing reusable components.
Rewrites
You are trying to use the same component to render a course for both your Route "/Courses/:id/:name" and as a list item on the Courses page, but one needs to have its data passed directly as props while the other gets its data from this.props.match.params. In order to solve this, we will make a component that handles just the rendering of the course. It gets its information from props, and is agnostic to where those props come from. This means we can use this component on any page of your app as long as we pass it a name and no. I used a function component, but it doesn't matter.
const CourseListItem = ({ name, no }) => {
return (
<div className="course">
<h1>{name}</h1>
<p>Course #{no}</p>
</div>
);
};
We can't send our Route directly to this component, because it wouldn't know the name and no. So we use an intermediate component that is responsible for setting the props of CourseListItem based on the router props (this.props.match.params). You could of course render other HTML or components and not just CourseListItem. I used a class for consistency with what you had before, but again it doesn't matter.
class SingleCoursePage extends Component {
render() {
return (
<CourseListItem
name={this.props.match.params.name}
no={this.props.match.params.id}
/>
);
}
}
In our Courses component, we loop through the courses from this.state and for each course we render the CourseListItem, setting the props name and no from the course object. See how we can use same component in different ways? If you wanted, you could make className be a prop of CourseListItem so that you could style it differently in different places.
class Courses extends Component {
state = {
courses: [
{ id: 1, title: "Angular - The Complete Guide" },
{ id: 2, title: "Vue - The Complete Guide" },
{ id: 3, title: "PWA - The Complete Guide" }
]
};
render() {
return (
<div>
<h1>Amazing Udemy Courses</h1>
<section className="Courses">
{this.state.courses.map((course) => {
return (
<Link
key={course.id}
to={"/Courses/" + course.id + "/" + course.title}
>
<CourseListItem name={course.title} no={course.id} />
</Link>
);
})}
</section>
</div>
);
}
}
As I explained, we are moving that Route for the single course page up to the top-level component, alongside the other routes.
class Assignment extends Component {
render() {
return (
<BrowserRouter>
<div>
<ul>
<li><Link to="/Users">Users</Link></li>
<li><Link to="/Courses">Courses</Link></li>
</ul>
<Switch>
<Route path="/Users" component={Users} />
<Route path="/Courses/:id/:name" component={SingleCoursePage} />
<Route path="/Courses" exact component={Courses} />
</Switch>
</div>
</BrowserRouter>
);
}
}
Code Sandbox Link - There's no CSS styling but all of the routing works!

Passing props to children not working In React

This should be super simple for some of you. I have a super simple app that I am making to teach myself the glory that is React and reactDom. Currently, I am pulling from an API (which actually works!), however, I am unable to see any data when rendering to the screen. Literally just two components. I am sure that I am using props or state wrong here, I just don't know where. It's possible that my map function is the problem as well.
Here is the code:
Parent:
import React from "react";
import ReactDOM from "react-dom";
import axios from 'axios'
import { Table } from './Table'
export class DataList extends React.Component {
state = {
articles: []
}
componentDidMount() {
axios.get('http://127.0.0.1:8000/api/portblog/')
.then(res => {
this.setState({
articles: res.data
})
console.log(res.data)
})
}
render() {
return(
<div>
<Table id={this.state.articles.id} articles={this.state.articles} />
</div>
)
}
}
export default DataList
And the child:
import React from "react";
import PropTypes from "prop-types";
import key from "weak-key";
export const Table = (props) => (
<div>
<h1>Welcome to the Article List Page Home</h1>
<li>{props.articles.map((article) => {
{article.titles}
})}</li>
</div>
);
export default Table;
The problem is that your map() call is not returning anything. You need to do something like:
<div>
<h1>Welcome to the Article List Page Home</h1>
{props.articles.map(article =>
<li>{article.titles}</li>
)}
</div>
I'm not exactly sure what your desired output is, but generally you map over data to generate a set of dom elements.
The problem is
<li>{props.articles.map((article) => {
{article.titles}
})}</li>
JSX expressions cannot be used in any arbitrary place. props.articles.map(...) is already an expression, so creating a new one wouldn't make sense.
{article.titles} inside a function creates a block that does nothing. Nothing is returned from map callback, the array isn't mapped to anything.
Depending on what should resulting layout look like, it should be either
<li>{props.articles.map((article) => article.titles)}</li>
output titles within single <li> tag, or
{props.articles.map((article) => <li>{article.titles}</li>)}
to output a list of <li> tags.
ESLint array-callback-return rule can be used to prevent the problem with callback return value.

Functions are not valid as a React child. This may happen if you return a Component instead of from render

I have written a Higher Order Component:
import React from 'react';
const NewHOC = (PassedComponent) => {
return class extends React.Component {
render(){
return (
<div>
<PassedComponent {...this.props}/>
</div>
)
}
}
}
export default NewHOC;
I am using the above in my App.js:
import React from 'react';
import Movie from './movie/Movie';
import MyHOC from './hoc/MyHOC';
import NewHOC from './hoc/NewHOC';
export default class App extends React.Component {
render() {
return (
<div>
Hello From React!!
<NewHOC>
<Movie name="Blade Runner"></Movie>
</NewHOC>
</div>
);
}
}
But, the warning I am getting is:
Warning: Functions are not valid as a React child. This may happen if
you return a Component instead of <Component /> from render. Or maybe
you meant to call this function rather than return it.
in NewHOC (created by App)
in div (created by App)
in App
The Movie.js file is:
import React from "react";
export default class Movie extends React.Component{
render() {
return <div>
Hello from Movie {this.props.name}
{this.props.children}</div>
}
}
What am I doing wrong?
I did encounter this error too because I didn't use the correct snytax at routing. This was in my App.js under the <Routes> section:
False:
<Route path="/movies/list" exact element={ MoviesList } />
Correct:
<Route path="/movies/list" exact element={ <MoviesList/> } />
So now the MoviesList is recognized as a component.
You are using it as a regular component, but it's actually a function that returns a component.
Try doing something like this:
const NewComponent = NewHOC(Movie)
And you will use it like this:
<NewComponent someProp="someValue" />
Here is a running example:
const NewHOC = (PassedComponent) => {
return class extends React.Component {
render() {
return (
<div>
<PassedComponent {...this.props} />
</div>
)
}
}
}
const Movie = ({name}) => <div>{name}</div>
const NewComponent = NewHOC(Movie);
function App() {
return (
<div>
<NewComponent name="Kill Bill" />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"/>
So basically NewHOC is just a function that accepts a component and returns a new component that renders the component passed in. We usually use this pattern to enhance components and share logic or data.
You can read about HOCS in the docs and I also recommend reading about the difference between react elements and components
I wrote an article about the different ways and patterns of sharing logic in react.
In my case i forgot to add the () after the function name inside the render function of a react component
public render() {
let ctrl = (
<>
<div className="aaa">
{this.renderView}
</div>
</>
);
return ctrl;
};
private renderView() : JSX.Element {
// some html
};
Changing the render method, as it states in the error message to
<div className="aaa">
{this.renderView()}
</div>
fixed the problem
I encountered this error while following the instructions here: https://reactjs.org/docs/add-react-to-a-website.html
Here is what I had:
ReactDOM.render(Header, headerContainer);
It should be:
ReactDOM.render(React.createElement(Header), headerContainer);
I had this error too. The problem was how to call the function.
Wrong Code:
const Component = () => {
const id = ({match}) => <h2>Test1: {match.params.id}</h2>
return <h1>{id}</h1>;
};
Whereas id is a function, So:
Correct code:
return <h1>{id()}</h1>;
Adding to sagiv's answer, we should create the parent component in such a way that it can consist all children components rather than returning the child components in the way you were trying to return.
Try to intentiate the parent component and pass the props inside it so that all children can use it like below
const NewComponent = NewHOC(Movie);
Here NewHOC is the parent component and all its child are going to use movie as props.
But any way, you guyd6 have solved a problem for new react developers as this might be a problem that can come too and here is where they can find the solution for that.
I was able to resolve this by using my calling my high order component before exporting the class component. My problem was specifically using react-i18next and its withTranslation method, but here was the solution:
export default withTranslation()(Header);
And then I was able to call the class Component as originally I had hoped:
<Header someProp={someValue} />
it also happens when you call a function from jsx directly rather than in an event. like
it will show the error if you write like
<h1>{this.myFunc}<h2>
it will go if you write:
<h1 onClick={this.myFunc}>Hit Me</h1>
I was getting this from webpack lazy loading like this
import Loader from 'some-loader-component';
const WishlistPageComponent = loadable(() => import(/* webpackChunkName: 'WishlistPage' */'../components/WishlistView/WishlistPage'), {
fallback: Loader, // warning
});
render() {
return <WishlistPageComponent />;
}
// changed to this then it's suddenly fine
const WishlistPageComponent = loadable(() => import(/* webpackChunkName: 'WishlistPage' */'../components/WishlistView/WishlistPage'), {
fallback: '', // all good
});
In my case, I was transport class component from parent and use it inside as a prop var, using typescript and Formik, and run well like this:
Parent 1
import Parent2 from './../components/Parent2/parent2'
import Parent3 from './../components/Parent3/parent3'
export default class Parent1 extends React.Component {
render(){
<React.Fragment>
<Parent2 componentToFormik={Parent3} />
</React.Fragment>
}
}
Parent 2
export default class Parent2 extends React.Component{
render(){
const { componentToFormik } = this.props
return(
<Formik
render={(formikProps) => {
return(
<React.fragment>
{(new componentToFormik(formikProps)).render()}
</React.fragment>
)
}}
/>
)
}
}
What would be wrong with doing;
<div className="" key={index}>
{i.title}
</div>
[/*Use IIFE */]
{(function () {
if (child.children && child.children.length !== 0) {
let menu = createMenu(child.children);
console.log("nested menu", menu);
return menu;
}
})()}
In my case I forgot to remove this part '() =>'. Stupid ctrl+c+v mistake.
const Account = () => ({ name }) => {
So it should be like this:
const Account = ({ name }) => {
In my case
<Link key={uuid()} to="#" className="tag">
{post.department_name.toString}
</Link>
changed with
<Link key={uuid()} to="#" className="tag">
{post.department_name.toString()}
</Link>
You should use
const FunctionName = function (){
return (
`<div>
hello world
<div/>
`
)
};
if you use Es6 shorthand function it will give error use regular old javascript function.

render array of object into a <li> in react.js

I read an article and the author critic below code, I wonder what's wrong with it. I was starting to learn React, too bad the author did not point out what's his problem with the code below. I tested the code below, it's running fine.
import React from 'react';
import './App.css';
const TodoItems = React.createClass({
getInitialState() {
return {
items : [
{id:1,name:"Gym"},
{id:2,name:"Jump"},
{id:3,name:"Racing"}
]
}
},
renderItem(){
return(
<ul>
{this.state.items.map((item,i) =>
<li key={i}>item.name</li>
)}
</ul>
)
},
render(){
return (
<renderItem />
)
}
})
ReactDOM.render(<TodoItems />,document.getElementById('app'));
The method renderItem should be outside as a functional or stateless component:
const RenderItem = (props) => {
return(
<ul>
{props.items.map((item,i) =>
<li key={i}>item.name</li>
)}
</ul>
)
};
The render method of the parent component should be:
render(){
return (
<RenderItem items={this.state.items} />
)
}
This is the standard way that we write React components. It causes maintainability issues when you write it that way.
In short, you code will not ensure component re-usability.
With React, you'll get the most of re-usability. In the above code, I can see that you are trying to render the items in the state in the function renderItem(). The need of using functions in any language is also to ensure re-usability. So, in React when you when you want to re-use a part which will return a HTML elements, make it as a separate component.
See the following fiddle
https://jsfiddle.net/Pranesh456/b6v6fxrj/1/
Here, I made the renderItem() as a separate component <RenderItem> which can be reused in n number of other components..

Categories

Resources