I've been scratching my head for hours trying to figure out why do I get a syntax error when trying to iterate a multidimensional array :
const InputPanel = React.createClass({
render() {
const { board } = this.props;
return(
<br />
{board.map(rows => {
rows.map(cell => <div className="digit">1</div>);
})
}
);
}
});
CodePen:
http://codepen.io/anon/pen/vXgmrR
I tried to add\modify parenthesis types and nothing helps.
Here is the view i'm trying to produce:
</br>
<div className="digit">1</div>
<div className="digit">1</div>
<div className="digit">1</div>
</br>
<div className="digit">1</div>
<div className="digit">1</div>
<div className="digit">1</div>
</br>
<div className="digit">1</div>
<div className="digit">1</div>
<div className="digit">1</div>
There are a couple of problems with the code.
Your rows.map(...) statement isn't actually outputting anything. You need to return the result of rows.map to have it rendered.
You could do this:
{board.map(rows => {
return rows.map(cell => <div className="digit">1</div>);
})
}
or this:
{board.map(rows => rows.map(cell => <div className="digit">1</div>))}
It's not clear to me if this in the render method will actually reference the component. I usually use ES2015 classes or stateless functions to create my components, simply because the logic seems clearer to me.
So, your component could be rewritten:
class InputPanel extends React.Component {
render() {
const { board } = this.props;
return(
<br />
{board.map(rows =>
rows.map(cell => <div className="digit">1</div>)
)
}
);
}
}
or, even more simply:
const InputPanel = ({ board }) => (
<br />
{board.map(rows => rows.map(cell => <div className="digit">1</div>))}
);
Now, I could be wrong about this - like I said, I'm not that familiar with the React.createClass way of doing things.
React is not going to like that bare <br /> in your component. render methods need to return a single element, so you're going to need to wrap everything in your render method in a <div> or some other element.
And this final one is the source of your syntax error: without that wrapping element, Javascript (or more accurately whatever system you're using to interpret JSX code) sees something like this:
return (
{ /* some Javascript code here */ }
);
which is not valid Javascript - you can't just return a code block like that.
With an enclosing <div>, the code looks like this:
return (
<div>
{ /* some Javascript code here */ }
</div>
);
which is valid JSX code and your JSX preprocessor can parse it.
So, to wrap it all up, the simplest form of your component would look something like this:
const InputPanel = ({ board }) => (
<div>
{board.map(rows => rows.map(cell => <div className="digit">1</div>))}
</div>
);
As an aside, I'd recommend looking into eslint to lint your code & catch errors like this. I try to use it religiously and I like to think it has improved my code quality :-)
for react native had an issue where I was all ready doing a map iteration
but had one key that was an object i was doing something like:
{this.state.some_data.map(item => (
<View style={styles.row} key={item.product_id}>
<Text style={styles.header}>{item.title}</Text>
// BUT item.variations_json IS a multi dimential object ???
</View>
))}
The Solution for me was ..
render() {
//...
const someVariation = (variation, product_id) => {
var vdata = [];
Object.entries(variation.data).map(([key,v]) => {
vdata.push(
<View key={key}>
<Text >{v.sku}</Text>
<Text >{v.title}</Text>
<Text>{v.price}</Text>
</View>
);
});
return vdata;
};
//...
then Later
{this.state.some_data.map(item => (
<View style={styles.row} key={item.product_id}>
<Text style={styles.header}>{item.title}</Text>
<someVariation data={item.variations_json} id={item.product_id}></someVariation>
</View>
))}
Related
I have a component which has child components, i want to render these child components with different Ids. They are getting their data from store.The problem is they are rendered but with the same item. how can this be solved?
MultiImages Component
const MultiImages: () => JSX.Element = () => {
const values = ['500', '406', '614'];
return (
<div>
{values.map((val, index) => {
return <OneImage key={index} projectID={val} />;
})}
</div>
);
};
export default MultiImages;
OneImage Component
const OneImage: () => JSX.Element = ({ projectID }) => {
const projectData = useProjectDataStore();
const { getProject } = useAction();
useEffect(() => {
getProject(projectID ?? '');
}, []);
return (
<>
<div>
<img
src={projectData.picture}
}
/>
<div>
<a>
{projectData.projectName}
</a>
</div>
</div>
</>
);
};
export default OneImage;
Your issue here - you are calling in a loop, one by one fetch your projects, and each call, as far as we can understand from your example and comments override each other.
Your are doing it implicitly, cause your fetching functionality is inside your Item Component OneImage
In general, the way you are using global state and trying to isolate one from another nodes is nice, you need to think about your selector hook.
I suggest you, to prevent rewriting too many parts of the code, to change a bit your selector "useProjectDataStore" and make it depended on "projectID".
Each load of next project with getProject might store into your global state result, but instead of overriding ALL the state object, you might want to use Map(Dictionary) as a data structure, and write a result there and use projectID as a key.
So, in your code the only place what might be change is OneImage component
const OneImage: () => JSX.Element = ({ projectID }) => {
// making your hook depended on **projectID**
const projectData = useProjectDataStore(projectID);
const { getProject } = useAction();
useEffect(() => {
// No need of usage **projectID** cause it will inherit if from useProjectDataStore
getProject();
}, []);
return (
<>
<div>
<img
src={projectData.picture}
}
/>
<div>
<a>
{projectData.projectName}
</a>
</div>
</div>
</>
);
};
export default OneImage;
And inside of your useProjectDataStore store result into a specific key using projectID.
Your component OneImage will return what's in the return statement, in your case:
<>
<div>
<img
src={projectData.picture}
/>
<div>
<a>
{projectData.projectName}
</a>
</div>
</div>
</>
This tag <></> around your element is a React.fragment and has no key. This is the reason you get this error.
Since you already have a div tag wrapping your element you can do this:
<div key={parseInt(projectID)}>
<img
src={projectData.picture}
/>
<div>
<a>
{projectData.projectName}
</a>
</div>
</div>
You can also change the key to Math.floor(Math.random() * 9999).
Note that passing the prop key={index} is unnecessary, and is not advised to use index as keys in a react list.
I want to make a component but i want that one accepts elements too. For example :
Component :
const Example = () => {
return (
<div>
//Some Elements will come here.
</div>
)
}
Another Page :
const App = () => {
return (
<Example>
<div>
<h1>Hello all </h1>
<p>I want that elements acceptable on my custom component </p>
</div>
</Example>
)
}
But i only can send props and i cant write anything inside of tags of my component. How can i make it ? Thanks for all!
React defined a special prop called children. That's what you exacly need.
Try like this
const Example = ({ children }) => {
return <div>{children}</div>;
};
const App = () => {
return (
<Example>
<div>
<h1>Hello all </h1>
<p>I want that elements acceptable on my custom component </p>
</div>
</Example>
);
};
You can use props.children
const Example = props => {
return <div>{props.children}</div>;
};
I'm following the react js tutorial, and I keep running into this issue
import React from "react";
import NewsCard from "../NewsCard/NewsCard";
const NewsCards = ({ articles }) => {
return (
<div>
{articles.map((article, i) => {
<NewsCard />;
})}
</div>
);
};
export default NewsCards;
Seems like your articles does not have default value as [].
You can change as follow. And you should give key attribute when using map function.
const NewsCards = ({ articles }) => {
const data = articles ? articles : []
return (
<div>
{data.map((article, i) => {
<NewsCard key={article.id}/>;
})}
</div>
);
};
Probably articles is not initialized when you try to map throught it. Try this:
{articles?.map((article, i) => {
<NewsCard />;
})}
OR
{articles && articles.map((article, i) => {
<NewsCard />;
})}
</div>
That way you will first make sure if articles exist
This means that the articles prop is undefined.
There are several ways to solve this. The first and easiest way is by implementing the following logic:
{articles?.length ? articles.map((article, i) => <NewsCard />) : "There are no articles here."}
Another way to solve this is by implementing React proptypes - you can read about this here.
Third and "hardest" (but probably best) way to solve this is by using a static type checking tool. Flow comes to mind, but you can use TypeScript too.
If you still need help, just like what the previous answers said, make sure that articles is initialized/defined by using the && operator to make that check. Also, based upon what you wrote, the map method is returning undefined since you specified a function body (using the function body bracket notation {} ) without a return statement. So instead write the map method like this:
<div>
{articles && articles.map((article, i) => <NewsCard />)}
</div>
or like this:
<div>
{articles && articles.map((article, i) => {
return <NewsCard />
})}
</div>
The first example implies an implicit return since an arrow function is being used and a function body is not present (there are no function body brackets { }).
While looking through our code base, I found code that looks a bit like this:
const Carousel = ({ items }) => {
return (
<CarouselOuter>
{items.map((item) => (
<CarouselItemWrapper>
<CarouselItem key={item.key}>
...
</CarouselItem>
</CarouselItemWrapper>
)}
</CarouselOuter>
);
}
Notice that the key prop is on CarouselItem, not CarouselItemWrapper, the component that's directly returned from items.map. This seems to work fine, and there are no warnings in the console, but it runs counter to every example I've seen using map in React.
I want know if there's a good argument (specifically in regards to performance) for rearranging the code with the key as shown below, or if this is just a stylistic choice:
const Carousel = ({ items }) => {
return (
<CarouselOuter>
{items.map((item) => (
<CarouselItemWrapper key={item.key}>
<CarouselItem>
...
</CarouselItem>
</CarouselItemWrapper>
)}
</CarouselOuter>
);
}
Side note: CarouselOuter, CarouselItem, and CarouselItemWrapper are all styled-components, but I doubt that's relevant.
I'm guessing they are the same since the output is the same, but is it the official shorthand in Redux or is it a Javascript property? I am following through the Redux documentation and have one component as such:
const App = () => (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
)
and another component as such:
const AddTodo = ({ dispatch }) => {
let input
return (
<div>
<form
onSubmit={e => {
e.preventDefault()
if (!input.value.trim()) {
return
}
dispatch(addTodo(input.value))
input.value = ''
}}
>
<input ref={node => (input = node)} />
<button type="submit">Add Todo</button>
</form>
</div>
)
}
I'm wondering if this is something to do with Javascript or React.
I understand that in Javascript, the arrow function needs to have a () like
(name, description) => ({name: name, description: description});
to describe that it is an object and not a plain function in case of inline, single-expression syntax, but I'm not sure if that applies here in the Redux example since the JSX portion is not an object. Please help me with my mistake.
Short answer, yes, as JSX and React follows the very same syntax the JavaScript uses, since JSX is merely a syntax extension to React. You may read more about JSX over here.
In addition, regarding your point about the redux, your redux should be written purely in JavaScript (or TypeScript), without any JSX syntax, since the main objective of your redux store is to maintain your application's state, rather than to render logic.
It's mostly for readability, you can omit the parentheses and it will function the same
const App = () =>
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
But when you have a body inside the component and want to return the JSX on a new line you have to wrap in in parentheses to avoid ASCI(automatic semicolon insertion)
const App = () => {
const x = 'something'
return (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
)
}