【问题标题】:Uncaught TypeError: Cannot read property of null, removing element from array javascript未捕获的类型错误:无法读取 null 的属性,从数组 javascript 中删除元素
【发布时间】:2017-05-24 01:29:57
【问题描述】:

当调用删除按钮上的 onClick 时,我试图从数组中删除一个元素,当单击该按钮时,我收到 Uncaught TypeError: Cannot read property 'name' of null

为什么会出现这个错误?

removeData(key) {
  console.log(key);
  const data = this.state.data;
  data[key] = null;
  this.setState({ data });
}

renderData(key){
    const user = this.props.data[key];
    console.log(user.name);
    console.log(user.id);
    return(
      <div key={key}>
          <li>  <strong> Name: </strong>  {user.name},
          <strong>  ID: </strong> {user.id} </li>
          <button onClick={() => this.props.removeData(key)}> Remove </button>
      </div>
    )
}

【问题讨论】:

  • 这是什么?...
  • 现在你的代码在你的console.log('user.name); 上失败了。所以你的this.props.data[key] 出了点问题,我们都无法真正分辨出它是什么。
  • 暗示user{user.name} 中为空
  • @cpugourou - 看起来像react

标签: javascript


【解决方案1】:

为什么会出现这个错误?

您将data[key] 明确设置为null

data[key] = null;

当组件重新渲染时,它可能会调用 renderData 并使用“删除”的键(因为该属性仍然存在,它的值只是 null)。 user 将是 null 并且访问 null.name 会引发错误。


根据您的实际需要,在您的renderData 方法中跳过null 值,或者实际上删除 带有

的条目
delete data[key];

分配null 不会删除属性:

var obj = {foo: 42};

// Doesn't actually remove the property
obj.foo = null;
console.log(obj);

// This removes the property
delete obj.foo;
console.log(obj);

我正在尝试从数组中删除一个元素

如果你真的有一个数组,那么还有更多的错误。 {...this.state.data} 不是克隆 array 的合适方法,因为您最终会得到一个 object

要在数组上正确执行此操作,您应该这样做

removeData(key) {
  // Assuming `key` is the index of the element
  // Create copy
  const data = Array.from(this.state.data);
  // Remove element at index `key`
  data.splice(key, 1);
  this.setState({ data });
}

【讨论】:

    【解决方案2】:

    试试:

    renderData(key){
        const user = this.props.data[key] || {}; // change
        console.log(user.name);
        console.log(user.id);
        return(
          <div key={key}>
              <li>  <strong> Name: </strong>  {user.name},
              <strong>  ID: </strong> {user.id} </li>
              <button onClick={() => this.props.removeData(key)}> Remove </button>
          </div>
        )
    

    在组件渲染时您的数据似乎还没有准备好,因此放入一个空白对象将允许组件在数据加载时呈现为空。

    编辑:您可以考虑:

    renderData(key){
            if (!this.props.data[key]) return null; //change
            const user = this.props.data[key];
            console.log(user.name);
            console.log(user.id);
            return(
              <div key={key}>
                  <li>  <strong> Name: </strong>  {user.name},
                  <strong>  ID: </strong> {user.id} </li>
                  <button onClick={() => this.props.removeData(key)}> Remove </button>
              </div>
            )
    

    这将在获取数据时隐藏组件。然后由您决定是否将数据加载给用户。你可以传递一个loading prop,当请求被触发时设置为 true,当请求返回数据并显示一些加载文本或动画时设置为 false。

    【讨论】:

    • 好的,现在它会在一瞬间删除正确的元素,但删除按钮仍然存在,在那一瞬间之后整个页面都会刷新。为什么页面会刷新?
    • @Omar:如果按钮在表单内,则单击按钮时将提交表单。默认情况下,按钮是提交按钮。您可以通过添加type="button" 使按钮充当普通按钮。
    【解决方案3】:

    从数组中移除对象

    从数组中删除对象的一个​​好方法是使用过滤器。使用过滤器可以保护我们免受使用 map 函数内部索引带来的错误的影响。 data.map((item,index) =&gt; &lt;div key={index} onClick={this.removeData(index)}&gt; {item.fruit} &lt;/div&gt;)。从阵列中删除对象时,这可能会导致严重问题。

    对此有何反应。

    我们不建议使用索引作为键,如果项目的顺序可能 改变。这可能会对性能产生负面影响,并可能导致问题 与组件状态。查看 Robin Pokorny 的文章 深入解释使用指数作为指标的负面影响 钥匙。如果您选择不为列表项分配显式键,则 React 将默认使用索引作为键。

    过滤方法

    这种方法采用对象的任何 id 并返回具有不同 id 的每个对象。

    this.setState({ data: temp.filter(item =&gt; item.id !== id) });

    工作示例

    import React, { Component } from 'react';
    import { render } from 'react-dom'; 
    class App extends Component {
      constructor() {
        super();
            this.state = { 
         data:[
         { fruit: "apple", id:1 },
         { fruit: "orange", id:2 }, 
         { fruit: "pineapple", id:3 },
        ],
        }
      }
          removeData = (id) => {
          const { data } = this.state;  
          const temp = data.slice();  
          this.setState({ data: temp.filter(item => item.id !== id) });
        }
        renderData = () =>{
            const { data } = this.state;
            return data.map((item) => {
             return  <div key={item.id}>
             <label> {item.fruit} </label>
             {item.id}
             <button onClick={() => this.removeData(item.id)}> Remove </button>
             </div>         
            })     
        }
      render() {
        return (
          <div>
            {this.renderData()}
          </div>
        );
      }
    }
    
    render(<App />, document.getElementById('root'));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-28
      • 2021-11-18
      • 2022-01-11
      相关资源
      最近更新 更多