I am trying to understand how Props work in React. The following code is giving an error - Error: Objects are not valid as a React child (found: object with keys {args})
const App = () => {
const course = 'Half Stack application development'
return (
<div>
<Header args={course}/> // Will an object be passed or just the string?
</div>
)
}
const Header = (agrs)=>{
console.log(agrs)
return (
<div>
<h1>{agrs}</h1>
</div>
)
}
When props are being passed, is an Object is passed encapsulating the fields or just the field values are passed?
why does the above code doesn't work?
Thanks
First off, you have a spelling mistake. Replace agrs with args. Secondly, props are passed as an object (dictionary), so you have one of two options:
const Header = (props) =>{
console.log(props.args)
return (
<div>
<h1>{props.args}</h1>
</div>
)
}
or object destructuring:
const Header = ({args}) =>{
console.log(args)
return (
<div>
<h1>{args}</h1>
</div>
)
}
Also, make sure to add props validation (your linter should warn you about this):
import PropTypes from "prop-types";
Header.propTypes = {
args: PropTypes.string.isRequired
};
Answer 1: Value is passed as a key with the same name as field you assigned it to in props object.
Answer 2:
const Header = (props)=>{
console.log(props.agrs)
return (
<div>
<h1>{props.agrs}</h1>
</div>
)
}
The code above will run fine.
Alternative to answer 2:
const Header = ({agrs})=>{
console.log(agrs)
return (
<div>
<h1>{agrs}</h1>
</div>
)
}
This will also run fine.
It uses object destructuring so you don't have to use props.agrs but just args works fine.
const App = () => {
const course = 'Half Stack application development'
return (
<div>
<Header args={course}/> // Will an object be passed or just the string?
</div>
)
}
const Header = ({agrs})=>{
console.log(agrs)
return (
<div>
<h1>{agrs}</h1>
</div>
)
}
Use object Destructuring like above or
const Header = (props)=>{
console.log(props.agrs)
return (
<div>
<h1>{props.agrs}</h1>
</div>
)
}
Find more here Components and Props.
Find more about Destructuring
import React from 'react';
class App extends React.Component {
render() {
return (
<div>
<h1>{this.props.headerProp}</h1>
<h2>{this.props.contentProp}</h2>
</div>
);
}
}
export default App;
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.jsx';
ReactDOM.render(<App headerProp = "Header from props..." contentProp = "Content
from props..."/>, document.getElementById('app'));
export default App;
enter image description here
Related
I have a simple react app in which i have to use useContext.
(btw im using vite + react)
here is my code for Context.jsx
import React, {useContext} from 'react';
const emailContext = React.createContext();
export const useEmail = () => useContext(emailContext);
export const emailProvider = ({children}) => {
const currentUser = "None";
const value = {
currentUser
}
return(
<emailContext.Provider value={value}>
{children}
</emailContext.Provider>
)
}
and heres how i am using the context
import "./styles.css";
import { useEmail } from "./Context/Context"
export default function App() {
const {currentUser} = useEmail();
return (
<div className="App">
<h1>Hello CodeSandbox {currentUser}</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
I am sure why I am getting error in this code.
some of the errors that I am getting
_useEmail is undefined (latest)
currentUser user is undefined
thing i have tried
Initialized createContext with some initial value (only intial value is visible).
using useContext() directy in the App.js (useContext(emailContext) return undefined)
instead of {children} used <children/>.
used useState instead of const currentUser in emailProvider
I am getting same problem even when I use typescript.
but none of the above helped.
You should wrapping app with <emailProvider></emailProvider> to using data in value={value}. Now it gets undefined from const emailContext = React.createContext();
Below code may help you analyse the flow , also check link for more details https://medium.com/technofunnel/usecontext-in-react-hooks-aa9a60b8a461
use useContext in receiving end
import React, { useState } from "react";
var userDetailContext = React.createContext(null);
export default function UserDetailsComponent() {
var [userDetails] = useState({
name: "Mayank",
age: 30
});
return (
<userDetailContext.Provider value={userDetails}>
<h1>This is the Parent Component</h1>
<hr />
<ChildComponent userDetails={userDetails} />
</userDetailContext.Provider>
);
}
function ChildComponent(props) {
return (
<div>
<h2>This is Child Component</h2>
<hr />
<SubChildComponent />
</div>
);
}
function SubChildComponent(props) {
var contextData = React.useContext(userDetailContext);
return (
<div>
<h3>This is Sub Child Component</h3>
<h4>User Name: {contextData.name}</h4>
<h4>User Age: {contextData.age}</h4>
</div>
);
}
React Newbie
I am coding in React. I am taking an object of JSON data from a GET request to an api, and trying to pass it as a prop in a component. Then I am mapping over it to make a list of "trail" objects.
I am getting this error in the console:
"Warning: Failed prop type: Invalid prop trail of type array supplied to TrailItem, expected object."
Here's the code for my app level component:
import React, { Component } from "react";
import "./App.css";
import Navbar from "./components/layout/Navbar";
import Trails from "./components/trails/Trails";
import axios from "axios";
class App extends Component {
state = {
trails: {},
};
async componentDidMount() {
const res = await axios.get(
`https://www.hikingproject.com/data/get-trails?lat=35.0844&lon=-106.6504&maxDistance=10&key=${process.env.REACT_APP_HIKING_PROJECT_KEY}`
);
console.log(res.data);
this.setState({ trails: res.data });
}
render() {
return (
<div className='App'>
<Navbar />
<div>
<Trails trails={this.state.trails} />
</div>
</div>
);
}
}
export default App;
As far as I can tell, there is no problem with the data. A console.log(res.data); returns an object, so I know the api request is working.
Here's the code for my "Trails" component:
import React, { Component } from "react";
import TrailItem from "./TrailItem";
class Trails extends Component {
render() {
return (
<div style={trailStyle}>
{Object.keys(this.props.trails).map((key) => (
<TrailItem key={key} trail={this.props.trails[key]} />
))}
</div>
);
}
}
const trailStyle = {
display: "grid",
gridTemplateColumns: "repeat(3, 1fr)",
gridGap: "1rem",
};
export default Trails;
I feel like maybe I'm not using the correct syntax to step into the object, and then further into the "trails" array, but I'm stumped. Thank you for you help!
EDIT
Here is the "TrailItem" code:
import React from "react";
import PropTypes from "prop-types";
const TrailItem = ({ trail: { name, location, imgSmall } }) => {
return (
<div className='card text-center'>
<img src={imgSmall} alt='trail' style={{ width: "25%" }} />
<h3>{name}</h3>
<p>{location}</p>
</div>
);
};
TrailItem.propTypes = {
trail: PropTypes.array.isRequired,
};
export default TrailItem;
I followed the advice of one of the comments and changed the PropType to array, and that fixed one of the warnings. But I still can't get a list of <TrailItem />.
Inside you App render method put this at the start:
if (!this.state.trails.length) {
return <div>Loading...</div>;
}
You can give trails a default or initial value of an empty array so the map function can be invoked. By using an empty array the component will map over an the empty array and return an empty array to render.
Default Value:
const Trails = ({ trails }) => {
console.log(trails.trails);
return (
<div style={trailStyle}>
{trails.map(trail => <TrailItem key={trail.id} trail={trail} />)}
</div>
);
};
TrailItem.propTypes = {
trail: PropTypes.array.isRequired,
};
TrailItem.defaultValue = {
trail: [],
};
Initial Value:
const Trails = ({ trails = [] }) => {
console.log(trails.trails);
return (
<div style={trailStyle}>
{trails.map(trail => <TrailItem key={trail.id} trail={trail} />)}
</div>
);
};
TrailItem.propTypes = {
trail: PropTypes.array.isRequired,
};
Note: This won't fix passing a prop of the incorrect type, but the prop validation react does will. It sounds like you got that bit sorted out though.
I solved it! Granted, I may not have been clear in my original question, but I figured out why I couldn't get access to the data object from the API.
I needed to step into the object one more time upon receiving the response in my App component:
this.setState({ trails: res.data.trails });
Once I did that, in my Trails component I needed Object.key() to make turn the "trails" prop into an array so I could .map() over it.
And finally, the "tricky" part was that I needed to use each "key" as the index for each "trail" prop I was trying to pass to <TrailItem />:
{Object.keys(trails).map((key) => (
<TrailItem key={key} trail={trails[key]} />
))}
everyone thanks for the help!
I have looked at several similar questions but have not been able to extrapolate their answers to solve my problem.
I am using a ReactJS application to consume JSON from a website. I'm using the code from https://pusher.com/tutorials/consume-restful-api-react and changing it to fit my situation.
Currently, when I view index.js, I get the error "TypeError:
assetList.assets is undefined." Given the the JSON and code below, what do I need to change to
display a list of the assets and their properties?
I would like something like the display to look like the Desired Display below.
Desired Display.
There are two 2 assets:<br/>
id: 1317 Filename: PROCESS_FLOW.pdf
id: 1836 Filename: 004527_FS.jpg
JSON consumed from website
{"totalNumberOfAssets":2,
"assets":[
{"id":"1317","attributes":{"Filename":["PROCESS_FLOW.pdf"]}},
{"id":"1836","attributes":{"Filename":["004527_FS.jpg"]}}
]}
components/assetList.js
import React from 'react'
const AssetList = ({assetList}) => {
return (
<div>
There are {assetList.totalNumberOfAssets} assets:
{assetList.assets.map((asset) => (
<div>
id: {asset.id} filename: {asset.filename}
</div>
))}
</div>
)
};
export default AssetList
App.js
import React, {Component} from 'react';
import AssetList from './components/assetList';
class App extends Component {
render() {
return (
<AssetList assetList={this.state.assetList} />
)
}
state = {
assetList: []
};
componentDidMount() {
fetch('http://ligitaddress/api/v1/asset')
.then(res => res.json())
.then((data) => {
this.setState({ assetList: data })
})
.catch(console.log)
}
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
On your first render, the value of this.state.assetList is an array:
state = {
assetList: []
};
However you are passing it into <AssetList>
const AssetList = ({assetList}) => {
return (
<div>
There are {assetList.totalNumberOfAssets} assets:
{assetList.assets.map((asset) => (
<div>
id: {asset.id} filename: {asset.filename}
</div>
))}
</div>
)
};
The line saying assetList.assets.map is trying to call map() on something that is undefined. (you can access the property assets on an array and it will be undefined) It seems like it expects assetList to be an object with an assets array in it, but in your parent component assetList is initialized to an array... in short you're confusing yourself as to what kind of data you expect to be where.
Either change your initial state to reflect how you expect it to be passed into <AssetList>:
state = {
assetList: {
assets: []
}
};
And/or change your <AssetList> component to properly check its prop:
const AssetList = ({assetList}) => {
return (
<div>
There are {assetList.totalNumberOfAssets} assets:
{Array.isArray(assetList.assets) && assetList.assets.map((asset) => (
<div>
id: {asset.id} filename: {asset.filename}
</div>
))}
</div>
)
};
This is happening because your components/assetList.js is trying to access assetList.assets on assetList.assets.map without it being defined.
When the API request is made and has not returned yet, the assets on assetList have not being defined, since assetList on App.js is initialized to an empty array.
You can replace the line on components/assetList.js with assetList.assets && assetList.assets.map(...) and that should do it
New to React - I am trying to use multiple contexts within my App component, I tried following the official guide on multiple contexts.
Here is my current code:
App.js
import React from "react";
import { render } from "react-dom";
import Login from "./Login";
import AuthContext from "./AuthContext";
import LayoutContext from "./LayoutContext";
import LoadingScreen from "./LoadingScreen";
class App extends React.Component {
render() {
const { auth, layout } = this.props;
return (
<LayoutContext.Provider value={layout}>
<LoadingScreen />
<AuthContext.Provider value={auth}>
<AuthContext.Consumer>
{auth => (auth.logged_in ? console.log("logged in") : <Login />)}
</AuthContext.Consumer>
</AuthContext.Provider>
</LayoutContext.Provider>
);
}
}
render(<App />, document.getElementById("root"));
Login.js
import React from "react";
class Login extends React.Component {
render() {
return (
<div></div>
);
}
}
export default Login;
AuthContext.js
import React from "react";
const AuthContext = React.createContext({
logged_in: false
});
export default AuthContext;
LayoutContext.js
import React from "react";
const LayoutContext = React.createContext({
show_loading: false
});
export default LayoutContext;
LoadingScreen.js
import React from "react";
import LayoutContext from "./LayoutContext";
class LoadingScreen extends React.Component {
render() {
return (
<LayoutContext.Consumer>
{layout =>
layout.show_loading ? (
<div id="loading">
<div id="loading-center">
<div className="sk-chasing-dots">
<div className="sk-child sk-dot1"></div>
<div className="sk-child sk-dot2"></div>
</div>
</div>
</div>
) : null
}
</LayoutContext.Consumer>
);
}
}
export default LoadingScreen;
Following the example, I never really understood how this.props (in App.js) could hold my different contexts.
Both auth and layout show up as undefined, this.props is empty, which will in turn cause my app to throw errors such as Cannot read property 'show_loading' of undefined
I immediately liked the example provided in the React documentation, but I can't get this to work.
I've made a small snippet to show you how you could structure your context providers and consumers.
My App component in this case is the root of the app. It has all the providers, along with the value for each one of them. I am not changing this value, but I could if I wanted to.
This then has a single child component, MyOutsideComponent, containing all the chained consumers. There are better ways to do this, I just wanted to show you, one by one, how chaining consumers work. In practice you can neatly reduce this using a few techniques.
This MyOutsideComponent has the actual component, MyComponent, which takes all the context elements and just puts their value on the page. Nothing fancy, the point was to show how the values get passed.
let FirstContext = React.createContext('first');
let SecondContext = React.createContext('second');
let ThirdContext = React.createContext('third');
let FourthContext = React.createContext('fourth');
let MyComponent = (props) => {
return (<span >{Object.values(props).join(" ")}</span>);
};
let App = (props) => {
return (
<FirstContext.Provider value="this is">
<SecondContext.Provider value="how you">
<ThirdContext.Provider value="pass context">
<FourthContext.Provider value="around">
<MyOutsideComponent />
</FourthContext.Provider>
</ThirdContext.Provider>
</SecondContext.Provider>
</FirstContext.Provider>
);
};
let MyOutsideComponent = () => {
return ( < FirstContext.Consumer >
{first =>
(< SecondContext.Consumer >
{second =>
(< ThirdContext.Consumer >
{third =>
(<FourthContext.Consumer >
{fourth =>
(<MyComponent first={first} second={second} third={third} fourth={fourth} />)
}
</FourthContext.Consumer>)
}
</ThirdContext.Consumer>)
}
</SecondContext.Consumer>)
}
</FirstContext.Consumer>);
}
ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Now, for the actual explanation. createContext gives you two actual components: a Provider and Consumer. This Provider, as you found out, has the value. The Consumer takes as child a single function taking one argument, which is your context's value.
This is where the docs are a bit unclear, and a bit which I hope I can help a bit. This does not get passed automatically in props unless the Provider is the direct parent of the component. You have to do it yourself. So, in the example above, I chained four consumers and then lined them all up in the props of my component.
You've asked about class-based components, this is how it ends up looking like:
let FirstContext = React.createContext('first');
let SecondContext = React.createContext('second');
let ThirdContext = React.createContext('third');
let FourthContext = React.createContext('fourth');
class MyComponent extends React.Component {
render() {
return ( < span > {Object.values(this.props).join(" ")} < /span>);
}
}
class App extends React.Component {
render() {
return (
<FirstContext.Provider value = "this is" >
<SecondContext.Provider value = "how you" >
<ThirdContext.Provider value = "pass context" >
<FourthContext.Provider value = "around" >
<MyOutsideComponent / >
</FourthContext.Provider>
</ThirdContext.Provider >
</SecondContext.Provider>
</FirstContext.Provider >
);
}
}
class MyOutsideComponent extends React.Component {
render() {
return (
<FirstContext.Consumer >
{ first =>
(< SecondContext.Consumer >
{ second =>
( < ThirdContext.Consumer >
{ third =>
( < FourthContext.Consumer >
{ fourth =>
( < MyComponent first = {first} second={second} third={third} fourth={fourth} />)
}
</FourthContext.Consumer>)
}
</ThirdContext.Consumer>)
}
</SecondContext.Consumer>)
}
</FirstContext.Consumer>
);
}
}
ReactDOM.render( < App / > , document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app" />
I'm using the following code which is being parsed by the linter eslint-plugin-react. It returns the warning:
"product is missing in props validation"
while i declare product in propTypes at the bottom and that i pass it to function. any idea ?
import React from 'react'
const ProductDesc = (props)=>({
render(){
return (
<div>
<h1>{props.product.headline}</h1>
<img src={props.product.images[0].imagesUrls.entry[2].url} alt="Thumbnail large pic"/>
<p>Yeah</p>
</div>
)
}
})
ProductDesc.propTypes = {
product: React.PropTypes.object
};
export default ProductDesc;
syntax should have been
const ProductDesc = (props)=>{
return (
<div>
<h1>{props.product.headline}</h1>
<p>Yeah</p>
</div>
)
}