英文:
React JSX error while iterating over object
问题
I have a JS object myFieldsObj as below;
{
field1: {value: 1},
field2: {value: 2},
field3: {value: 3}
}
In my JSX, I want to iterate over this and render some output.
<MyCustomDialog>
{
<>
{Object.keys(myFieldsObj).map((key, index) => (
<div key={index}>
<Field field={myFieldsObj[key]} />
</div>
))}
</>
}
</MyCustomDialog>
However the above is giving an error saying
Uncaught ReferenceError: index is not defined
Not sure what the issue is with the syntax.
英文:
I have a JS object myFieldsObj as below;
{
field1: {value: 1},
field2: {value: 2},
field3: {value: 3}
}
In my JSX, I want to iterate over this and render some output.
<MyCustomDialog>
{
<>
Object.keys(myFieldsObj).map((key, index) => {
<div key={index}>
<Field field={myFieldsObj[key]} />
</div>
})
</>
}
</MyCustomDialog>
However the above is giving an error saying
> Uncaught ReferenceError: index is not defined
Not sure what the issue is with the syntax.
答案1
得分: 1
以下是翻译的内容:
-
由于您正在尝试在另一个自定义组件(
MyCustomDialog
)中创建Field
组件,您需要让MyCustomDialog
渲染这些children
。您可以通过确保从其props访问children
并在(语义化的)元素内返回它来实现。注意:在此将子元素包装在呈现元素中意味着您可以在其他组件中不使用React片段(<></>
)。 -
确保在
map
内部返回每个Field
组件。您正在使用花括号,因此需要显式的return
。也没有真正需要单独的div
包装器。只需将键应用于字段组件即可。 -
您可能会发现使用数组而不是对象更容易处理数据。请注意,数组中的对象都具有
id
属性,您可以将其值用作map
迭代中的键,而不是通常应避免使用的map
的索引。
在这个示例中,在迭代中,我将每个完整的对象作为data
传递给props,以便在Field
组件中同时访问name
和value
。
如果您需要更多信息,请告诉我。
英文:
To try and tie TJ's and Jon's comments up in a working example with some additional commentary.
-
Since you're trying create
Field
components within another bespoke component (MyCustomDialog
) you'll need to haveMyCustomDialog
render thosechildren
. You can do that by ensuring thatchildren
is accessed from its props and returned inside a (semantic) element (here:section
). Note: wrapping the child elements in a presentation element here means you can do away with the React fragment (<>
) in your other component. -
Make sure that you return each
Field
component within themap
. You're using curly braces so an explicitreturn
is required. There's also no real need for that separatediv
wrapper. Just apply the key to the field component instead.
(More after the first example...)
<!-- begin snippet: js hide: false console: true babel: true -->
<!-- language: lang-js -->
const { useState } = React;
// MyCustomDialog needs to be able to
// render its child elements. Since we wrap them
// in a section element we can do without the
// React fragment in the Example component
function MyCustomDialog({ children }) {
return <section>{children}</section>;
}
// Basic field component
function Field({ field }) {
return <div>{field.value}</div>;
}
// Passing in the data to the component, and
// iterating over it. On each iteration a new
// field component it created with a new field object
function Example({ myFieldsObj }) {
return (
<MyCustomDialog>
{Object.keys(myFieldsObj).map((key, index) => {
return <Field key={index} field={myFieldsObj[key]} />
})}
</MyCustomDialog>
);
}
const myFieldsObj = {
field1: { value: 1 },
field2: { value: 2 },
field3: { value: 3 }
};
const node = document.getElementById('root');
const root = ReactDOM.createRoot(node);
root.render(<Example myFieldsObj={myFieldsObj} />);
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.min.js"></script>
<div id="root"></div>
<!-- end snippet -->
-
You may find it easier using an array for your data instead of an object. Note here the objects in the array all have an id property the value of which you can use for the key in the map iteration instead of
map
's own index which you should generally avoid.In this example, in the iteration, I'm adding the each complete object as
data
in the props so I can access both thename
and thevalue
in theField
component.
<!-- begin snippet: js hide: false console: true babel: true -->
<!-- language: lang-js -->
const { useState } = React;
// MyCustomDialog needs to be able to
// render its child elements. Since we wrap them
// in a section element we can do without the
// React fragment in the Example component
function MyCustomDialog({ children }) {
return <section>{children}</section>;
}
// Basic field component
function Field({ data }) {
return (
<div>
<h4>{data.name}</h4>
<p>{data.value}</p>
</div>
);
}
// Passing in the data to the component, and
// iterating over it. On each iteration a new
// field component it created with a new field object
function Example({ myFields }) {
return (
<MyCustomDialog>
{myFields.map(obj => {
return (
<Field
key={obj.id}
data={obj}
/>
);
})}
</MyCustomDialog>
);
}
const myFields = [
{ id: 1, name: 'field1', value: 1 },
{ id: 2, name: 'field2', value: 2 },
{ id: 3, name: 'field3', value: 3 }
];
const node = document.getElementById('root');
const root = ReactDOM.createRoot(node);
root.render(<Example myFields={myFields} />);
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.min.js"></script>
<div id="root"></div>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论