It looks like you are trying to use a React component as if it were a React hook.
My suggestion would be to re-write as a React hook and then you should be able to correctly log the chosen pokemon:
Landing Becomes:
import { usePokemon } from "../../component/returnPokemon";
export const Landing = () => {
const { chosenPokemon } = usePokemon("ditto");
console.log(chosenPokemon);
return (
<>
<h1>Landing</h1>
{chosenPokemon.name}
</>
);
};
Instead write ReturnPokemon as a React Hook:
import { useDitto } from "../../context/ditto";
import { useCharizard } from "../../context/charizard";
export function usePokemon(pokemon) {
const { ditto } = useDitto();
const { charizard } = useCharizard();
if (pokemon === "ditto") {
return { chosenPokemon: ditto };
} else if (pokemon === "charizard") {
return { chosenPokemon: charizard };
} else {
return null;
}
};
Answer from Jack Gore on Stack OverflowIt looks like you are trying to use a React component as if it were a React hook.
My suggestion would be to re-write as a React hook and then you should be able to correctly log the chosen pokemon:
Landing Becomes:
import { usePokemon } from "../../component/returnPokemon";
export const Landing = () => {
const { chosenPokemon } = usePokemon("ditto");
console.log(chosenPokemon);
return (
<>
<h1>Landing</h1>
{chosenPokemon.name}
</>
);
};
Instead write ReturnPokemon as a React Hook:
import { useDitto } from "../../context/ditto";
import { useCharizard } from "../../context/charizard";
export function usePokemon(pokemon) {
const { ditto } = useDitto();
const { charizard } = useCharizard();
if (pokemon === "ditto") {
return { chosenPokemon: ditto };
} else if (pokemon === "charizard") {
return { chosenPokemon: charizard };
} else {
return null;
}
};
There is no need to use useState if you are going to return it anyway. You cannot return an object in a component. You have to return some JSX element like and you can have your object inside.
Assumptions made here:
- ditto, charizard are strings. if not just do JSON.stringify(ditto) to cast object as string
Landing:
export const Landing = () => {
return (
<>
<h1>Landing</h1>
<ReturnPokemon pokemon="ditto" />
</>
);
};
ReturnPokemon:
import { useDitto } from "../../context/ditto";
import { useCharizard } from "../../context/charizard";
export const ReturnPokemon = ({ pokemon }) => {
const { ditto } = useDitto();
const { charizard } = useCharizard();
if (pokemon === "ditto") {
return <div>{ditto}</div>;
}
if (pokemon === "charizard") {
return <div>{charizard}</div>;
}
return <div></div>;
};
reactjs - Why can't a react stateless function return an array? - Stack Overflow
[@types/react] React Component does not allow returning an array of React Elements
reactjs - Typescript + React, rendering an array from a stateless functional component - Stack Overflow
React functional components: return an array list inside an array of nested objects
Videos
if found this in react docs here is the link does this works i tried but it is not working
link to doc
render() { // No need to wrap list items in an extra element! return [ // Don't forget the keys :) <li key="A">First item</li>, <li key="B">Second item</li>, <li key="C">Third item</li>, ]; }Now you can return an array , try out the React 16 Beta
I think your issue rely on the inability for stateless functions to handle anything else than a single JSX element. It simply doesn't know how to render properly your array.
I would advice you to wrap your array elements in a root <div> like this to make it work:
function DeliveryPreference (props) {
return (
<div>
<h4>Delivery Preference</h4>
<div className='yesNoCheckbox'>
<input type="radio" value={'tube'} onChange={props.onChange} id='tube' checked={props.value === 'tube'}/> <label htmlFor='tube'>Tube</label> <br/>
<input type="radio" value={'plate'} onChange={props.onChange} id='plate' checked={props.value === 'plate'}/> <label htmlFor='plate'>Plate</label><br/>
</div>
</div>
)
}
Or else decompose your two JSX elements in different functions.
Until the open Definitely Typed issue has been resolved, the best work around is probably just to use <React.Fragment/> instead. For functional purposes, I don't think there is any difference:
const Bar: React.SFC<CheckoutProps> = (props) => {
return (
<React.Fragment>
<div>bar</div>
<div>baz</div>
</React.Fragment>
);
};
"You can now return an array of elements from a component’s render method."
The array of JSX is being compiled by React.Components render method. A stateless functional component lacks that render method.
You could either wrap your array of elements in a parent div instead of the array or use a regular class component.
You can map the list of stations to ReactElements.
With React >= 16, it is possible to return multiple elements from the same component without needing an extra html element wrapper. Since 16.2, there is a new syntax <> to create fragments. If this does not work or is not supported by your IDE, you can use <React.Fragment> instead. Between 16.0 and 16.2, you can use a very simple polyfill for fragments.
Try the following
// Modern syntax >= React 16.2.0
const Test = ({stations}) => (
<>
{stations.map(station => (
<div key={station.call} className='station'>{station.call}</div>
))}
</>
);
// Modern syntax < React 16.2.0
// You need to wrap in an extra element like div here
const Test = ({stations}) => (
<div>
{stations.map(station => (
<div className="station" key={station.call}>{station.call}</div>
))}
</div>
);
// old syntax
var Test = React.createClass({
render: function() {
var stationComponents = this.props.stations.map(function(station) {
return <div className="station" key={station.call}>{station.call}</div>;
});
return <div>{stationComponents}</div>;
}
});
var stations = [
{call:'station one',frequency:'000'},
{call:'station two',frequency:'001'}
];
ReactDOM.render(
<div>
<Test stations={stations} />
</div>,
document.getElementById('container')
);
Don't forget the key attribute!
https://jsfiddle.net/69z2wepo/14377/
I have an answer that might be a bit less confusing for newbies like myself. You can just use map within the components render method.
render () {
return (
<div>
{stations.map(station => <div key={station}> {station} </div>)}
</div>
);
}
You need to have additional object which will have pair of key and value which will be destructured as your props to the React Component.
const props = {
figures, // shorter way of writing figures: figures
// Any other objects you'd like to pass on as props
}
and then, you can do:
<FPS {...props} />
Updated Code
Basically you can only destructure an object in the React Component because then the destructured object's key-value pairs will become props to the component.
For better understanding,
const arr = [{ a: 'a'}]
{...arr}
will give:
{
0: {a: 'a'}
}
because 0 is the key as it is an array as opposed to an object, so what you were really doing was passing a prop with name 0 instead of figures and figures was undefined and hence the error.
You can use something like this:
import React from "react";
import Figure from './Figure';
import { render } from "react-dom";
const App = () => {
const figures = [
{
config: 112,
description: "description text 1"
},
{
config: 787,
description: "description text 2"
}
];
return (
<div>
{
figures.map((figure, key) => {
return <Figure key={key} {...figure}/>
})
}
</div>
);
};
render(<App />, document.getElementById("root"));
And create a component called Figure like this:
import React from "react";
const Figure = (props) => {
return (
<div>
<p>{props.description}</p>
<p>{props.config}</p>
</div>
);
};
export default Figure;
Have you consider using the new React Fragments? (in v16)
This would be the simplest solution as it would by pass the whole array/key issue.
If you need to pass key, then I'd suggest to simply require the components to have the keys. This is how React works, so I wouldn't suggest you to hide this behavior behind an interface that might not be predictable.
If you really need to do this, then you can use React.cloneElement to clone the element and inject new properties:
React.cloneElement(element, { key: 'foo' });
If you’re always going to want to render all the components in your components file then you’re probably better off wrapping them in a React.Fragments tag.
Best practise is just to export this as a simple function that returns the components rather than as a constant.
So...
const Components = props => {
return (
<React.Fragment>
<ComponentOne/>
<ComponentTwo/>
</React.Fragment>
)
}
export default Components
That allows you to put multiple components next to each other without a DOM element containing them.
You should then just be able to render that by using it as a normal component and it’ll render all of them, so just import it then...
<Components />
Otherwise, if you want to treat them like an array, you have a function for free on the React object you’ve imported...
React.Children.toArray(arrayOfComponents)
You pass it an array of components (like in your original question) and it allows you to sort and slice it if you need to then you should be able to just drop it in the return of your render function