开发者问题收集

TypeError:当组件在 React 中上传文件时,无法读取未定义的属性“map”

2021-02-24
108

React 新手在这里。 当 props.submitClk === true(绿灯表示我的上传按钮已被点击,并且文件已从另一个组件的表单发送)时,我尝试使用新技术对象更新状态 setList,但目前只是“SomeObject”。点击后,我收到“TypeError 无法读取未定义的属性‘map’”。我尝试摆弄一些条件,但经过几个小时的尝试后没有运气。这是一个异步问题,并且映射发生得太快了吗?当我删除对象时,handleRemove 工作正常。如果我删除 if 语句下的函数,它不会在表单提交时抛出错误。此外,对象将变得更大,这就是它目前以这种方式嵌套的原因。感谢您的回答。

function SampleData(props) {
const [list, setList] = React.useState( [
        {
            closedguard: [
                {
                    name: "Armbar",
                    link: "",
                    x: "X",
                    id: "1",
                },
                {
                    name: "Triangle",
                    link: "",
                    x: "X",
                    id: "2",
                },
                {
                    name: "Omaplata",
                    link: "",
                    x: "X",
                    id: "3",
                },
        ] } 
    ] );  
 
    if( props.submitClk === true) {
        setList([...list, 'SomeObject'])
      }

  const handleRemove = (id) => {
    const newList = list[0].closedguard.filter(move => move.id !== id);
    setList([{ closedguard: newList }]);
};

    return (
        <div className="guard">
    
            <ul className="techUl">
                {" "}
                Closed Guard
                {list.map((pos) =>
                        pos.closedguard.map((move, id) => (
                            <li
                                key={id}
                                className="techLi"
                                                
                                >{move.name}
                                <span onClick={(id) => handleRemove(move.id)}> {move.x}</span>
                            </li>
                        ))
                    )}
            </ul>       
        </div>
    );
}
3个回答

首先,如果没有 someObject ,您将面临 过多的重新渲染。React 会限制渲染次数以防止无限循环。

然后,您正在更新嵌套对象:

[
        {
            closedguard: [
                {
                    name: "Armbar",
                    link: "",
                    x: "X",
                    id: "1",
                },
                {
                    name: "Triangle",
                    link: "",
                    x: "X",
                    id: "2",
                },
                {
                    name: "Omaplata",
                    link: "",
                    x: "X",
                    id: "3",
                },
            ] 
        }
]

对象数组,然后对象 closedguard 位于其中,它是一个数组。

因此,您可以在条件内执行的操作是

// think is the some objects
const newObject = [
      {
        name: "test1",
        link: "",
        x: "X",
        id: "5"
      },
      {
        name: "test2",
        link: "",
        x: "X",
        id: "56"
      }
    ];
    setList([{ closedguard: [...list[0].closedguard, ...newObject] }]);

而不是

setList([...list, 'SomeObject'])
Nafis
2021-02-24

要更新您的状态 list 的 closeguard 数组,您可以查看 @Nafis 的回答,但您应该使用 useEffect 钩子来运行副作用。尝试将此逻辑与 @Nafis 的回答结合起来以更新状态 -

if( props.submitClk === true) { setList([...list, 'SomeObject'])

在 useEffect 钩子内,如下所示

useEffect(()=>{
if( props.submitClk === true) {
    setList([...list, 'SomeObject']) }

},[list])

现在修改 list.map 函数如下,那么您将不会收到 map 未定义错误

{list.length > 0 && list.map((pos) =>
                    pos.closedguard.map((move, id) => (
                        <li
                            key={id}
                            className="techLi"
                                            
                            >{move.name}
                            <span onClick={(id) => handleRemove(move.id)}> {move.x}</span>
                        </li>
                    ))
                )}

让我知道它是否有效

Rmcr714
2021-02-24

如果您想更新嵌套对象以将元素添加到 closedguard: 属性数组,请检查@Nafis 的回答。

我认为问题在于您添加的新对象没有 closedguard 属性,因此 map 函数无法映射该对象。

如果添加具有该属性的对象,它将起作用,例如:

const objToAdd = {closedguard: [
    {
    name: "newObj1",
    link: "",
    x: "X",
    id: "3",
   },
    {
      name: "newObj2",
      link: "",
      x: "X",
      id: "3",
    }] 
  }

如果您正在添加具有另一个属性的对象,则可能需要映射的是相应的键,以确保您从对象中获取属性,因此需要更改

pos.closedguard.map((move, id) => (

通过:

pos[Object.keys(pos)[0]].map((move, id) => ( 例如。

所以在如果您的对象没有 closedguard ,则该对象的第一个属性将被映射。

发布我提案的完整回报只是为了让我的提案清晰:

return (
    <div className="guard">
      <ul className="techUl">
        {" "}
        Closed Guard
        {list.map((pos) =>
          pos[Object.keys(pos)[0]].map((move, id) => ( //CHANGE HERE
            <li
              key={id} className="techLi"         
              >{move.name}
              <span onClick={(id) => handleRemove(move.id)}> {move.x}</span>
            </li>
          ))
        )}
      </ul> 
      <button onClick={handleOnClick}>Button</button>      
  </div>
  );
rustyBucketBay
2021-02-24