【问题标题】:Passing functions through props from parent states in ReactJS在 ReactJS 中通过来自父状态的 props 传递函数
【发布时间】:2018-01-16 19:32:36
【问题描述】:

所以这可能有点混乱,所以我会尽量简化它。

我的状态在我的父组件App.js 中保存了一组对象。这是一个对象的示例。

{
category: "sample category",
API: "API URL",
active: function()
}

在我的子组件Category.js 中,我将该数组通过一个道具传递。子渲染一个ul,然后映射到数组上,为每个类别创建一个li。每个列表项都应该有一个 onClick 事件,触发对象中关联的active: function()

由于某种原因,这不起作用。如果我运行一个函数是简单的console.log("success") 的测试,那没问题。因此,列表项正在获取该功能并通过我的道具正常运行。

这让我相信问题出在我正在运行的实际功能上。我要运行的函数是这个(位于App.js

function() {
  this.setState({categoryActive: "https://opentdb.com/api.php?amount=20&category=11"});
  this.setState({showQuestions: true});
}

正在设置的那些状态位于App.js 中,并且该函数也位于App.js 中,但正在通过Category.js 中的列表项的道具运行。这是我的问题吗? App.js的状态不能通过子组件run来调整吗?


编辑:这里有更多代码可以帮助找出解决方案。

实际错误:Uncaught TypeError: Cannot read property 'setState' of undefined 在 catMovies (App.js:71)

App.js:71 是我的catMovies() 函数的this.setState({categoryActive: "https://opentdb.com/api.php?amount=20&category=11"});

我的App.js 构造函数

constructor(props) {
super(props);
this.state = {
  showCategories: false,
  showQuestions: false,
  isQuestionLoaded: false,
  categories: [{
    category: "movies",
    API: "https://opentdb.com/api.php?amount=10&category=11",
    active: this.catMovies
  }, {
    category: "sports",
    API: "https://opentdb.com/api.php?amount=10&category=21",
    active: this.catSports
  }, {
    category: "books",
    API: "https://opentdb.com/api.php?amount=10&category=10",
    active: this.catBooks
  }, {
    category: "videogames",
    API: "https://opentdb.com/api.php?amount=10&category=15",
    active: this.catVideogames
  }, {
    category: "general",
    API: "https://opentdb.com/api.php?amount=10&category=9",
    active: this.catGeneral
  }, {
    category: "everything",
    API: "https://opentdb.com/api.php?amount=10",
    active: this.catEverything
  }],
  categoryActive: "",
  questionNumber: 0,
  questionTotal: null,
  correct: [],
  score: 0,
  showFinal: false,
  testState: "test"
};
this.showCategories = this.showCategories.bind(this);
this.showQuestions = this.showQuestions.bind(this);
this.catMovies = this.catMovies.bind(this);
}

这是App.js中的实际功能:

catMovies() {
  this.setState({categoryActive: "https://opentdb.com/api.php?amount=20&category=11"});
  this.setState({showQuestions: true});
}

这是来自 App.js 的返回,它调用子组件:

<Categories categoryList={ this.state.categories } onClick={ this.catMovies } />

最后,这是使用所有这些的子组件中的地图:

const categoryListItems = this.props.categoryList.map(cat =>
  <a href="#questionsContainer" key={cat.category + "link"}>
    <li onClick={cat.active} key={cat.category}>
      {cat.category}
    </li>
  </a>
);

【问题讨论】:

  • 您需要发布更多的父子组件代码。
  • @Prakashsharma 我在编辑中添加了更多代码。谢谢
  • 我怀疑将函数存储在状态中是一种好习惯。我会按其类别有条件地传递处理程序,而不是将其存储在状态中。
  • @Sagivb.g 是的,不知道为什么我认为将它存储在状态中是一个好主意,因为我可以在我的渲染中定义一个变量中的数组。这似乎已经修复了错误。现在我只需要弄清楚如何确保我的状态更改在渲染之前生效:S 谢谢!
  • 技术上你可以存储它,但你的绑定是错误的(请参阅我的答案以获得清晰和示例)

标签: reactjs


【解决方案1】:

您的问题在于处理程序的绑定。
不要像在构造函数中那样覆盖处理程序,而应该直接在状态初始化中进行:

this.state = {
  showCategories: false,
  showQuestions: false,
  isQuestionLoaded: false,
  categories: [{
    category: "movies",
    API: "https://opentdb.com/api.php?amount=10&category=11",
    active: this.catMovies.bind(this) // <-- you need to bind here
  },
 //...

这是一个包含两种模式的运行示例,请注意turnOff 处理程序将如何抛出与您得到的相同的错误:

const LightBall = ({ on }) => {
  return (
    <div>{`The light is ${on ? 'On' : 'Off'}`}</div>
  );
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      lightOn: false,
      toggle: this.toggleLight.bind(this), // this will work
      turnOff: this.turnOff // this will not work
    };
    this.turnOff = this.turnOff.bind(this);
  }

  toggleLight(){this.setState({ lightOn: !this.state.lightOn })};

  turnOff() { this.setState({ lightOn: false }) };

  render() {
    const { lightOn, toggle, turnOff } = this.state;
    return (
      <div>
        <button onClick={toggle}>Toggle Light</button>
        <button onClick={turnOff}>Turn Off</button>
        <LightBall on={lightOn} />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

【讨论】:

  • 我假设您指的是我的评论。如果是这样,我没有说将数组移出state,而是将处理程序移出状态。最好存储可序列化的数据,不是强制性的,而是首选。
【解决方案2】:

这个问题可能是因为在这个函数中

function() {
  this.setState({categoryActive: "https://opentdb.com/api.php?amount=20&category=11"});
  this.setState({showQuestions: true});
}

this 是指调用函数的类。

您可以通过将函数绑定到 App 组件来解决此问题,然后使用 bind() 将数组传递给子组件(在此处查看更多信息 https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

或者,如果您在 App 组件中定义它以自动将其范围绑定到该组件,则可以使用箭头函数,所以

{
category: "sample category",
API: "API URL",
active: () => {
    this.setState({categoryActive: "https://opentdb.com/api.php?amount=20&category=11"});
    this.setState({showQuestions: true});
  }
}

在此处查看有关箭头功能的更多信息https://babeljs.io/learn-es2015/#arrows-and-lexical-this

【讨论】:

  • 我认为这不是问题,因为我已将其绑定到我的函数中。我在问题中添加了更多代码,以便为人们提供更多信息。
猜你喜欢
  • 1970-01-01
  • 2017-05-13
  • 2016-10-05
  • 2016-09-29
  • 2020-09-15
  • 2023-02-13
  • 2021-10-20
  • 2019-07-14
  • 2015-05-10
相关资源
最近更新 更多