你如何将 onClick 函数传递给 React 中的孙组件?

时间:2021-05-07 08:42:19

标签: javascript reactjs

我刚刚开始使用 React,根据我的情况调整井字游戏教程。 我正在尝试单击孙组件以更改祖父组件的状态。代码如下:

class App extends React.Component {
  
  constructor(props) {
    super(props);
    this.state = {
      fields: [
        {
          id: 1,
          show: false
        },
        {
          id: 2,
          show: false
        }
      ]
    }
  }

  handleClick(i) {
    const fields = this.state.fields.slice();
    fields[i].show = true;
    this.setState({fields: fields});
  }
  
  render() {return <Preview />}
      
}

const Preview = (props) => {
  
  return (
    <div className="preview">
      {props.fields.map((field) => (
        <Field data={field} key={field.id} onClick={ props.onClick(field.id) }/>
      ))}
    </div>
  );
};

const Field = props => {
  
  return (
    <div className="field" onClick={ props.onClick } />
  );
};

我收到一个类型错误:无法从这一行读取未定义的属性“状态”:

handleClick(i) {
const fields = this.state.fields.slice();

2 个答案:

答案 0 :(得分:1)

问题

    this 类的
  1. App 未绑定到 handleClick 函数。这是 TypeError: Cannot read property 'state' of undefined 错误的原因。
  2. 您正在改变您的状态对象。对数组进行切片会创建一个新的数组引用,但 fields[i].show = true; 会改变状态中的对象引用。
  3. 您没有将 fieldsonClick 道具传递给 Preview
  4. onClick 中未正确调用 Preview 回调。

解决方案

  1. this 绑定到处理程序或转换为箭头函数使其自动绑定。

    constructor(props){
      ...
      this.handleClick = this.handleClick.bind(this);
    }
    

    handleClick = (i) => { ..... };
    
  2. 不要改变状态。浅拷贝状态然后更新属性。

    handleClick = (id) => {
      this.setState(prevState => ({
        fields: prevState.fields.map((field) => {
          return field.id === id ? {
            ...field,
            show: true,
          } : field;
        }),
      }));
    };
    
  3. fieldshandleClick 作为 onClick 传递给 Preview

    render() {
      return (
        <Preview
          fields={this.state.fields}
          onClick={this.handleClick}
        />
      );
    }
    
  4. 使用 id 正确调用 props.onClick

    {props.fields.map((field) => (
      <Field
        data={field}
        key={field.id}
        onClick={() => props.onClick(field.id)}
      />
    ))}
    

答案 1 :(得分:0)

我已经添加了一些解释,请查看评论

  // [...]

  render() {
    // Here you need to pass "fields" and "handleClick" as props:
    return <Preview fields={this.state.fields} onClickField={this.handleClick} />
  }
      
}

const Preview = (props) => {
  // Here you get the props:
  const { fields, onClickField } = props;

  // Your onclick was a function call instead of just a function
  return (
    <div className="preview">
      {fields.map((field) => (
        <Field 
          data={field}
          key={field.id}
          onClick={() => onClickField(field.id) }
        />
      ))}
    </div>
  );
};

const Field = props => {
  
  return (
    <div className="field" onClick={ props.onClick } />
  );
};