如何通过祖父母组件更改特定子组件的状态?

时间:2016-02-19 20:14:25

标签: reactjs

我的应用有布局组件,它是主要组件,它有两个 Bookshelf 组件,每个 Bookshelf 组件有五个预订组件。我如何在第二个 Bookshelf ,第五个 Book state.taken更改 true false 中更改< strong>布局组件?

它看起来像这样:

Layout.js

    export default class Layout extends React.Component {
  render() {
    var bookshelves = [
      1,2
    ].map((bookshelf_id, i) => <Bookshelf key={i} bookshelf_id={bookshelf_id}/>);
    return (
      <div>
      {bookshelves}
      </div>
    );
  }
}

Bookshelf.js

export default class Bookshelf extends React.Component {
  render() {
    var books = [
      1,2,3,4,5
    ].map((book_id, i) => <Book key={i} book_id={book_id}/>);
    return (
      <table>
      <h1>Shelf{this.props.bookshelf_id}</h1>
      {books}
      </table>
    );
  }
}

Book.js

export default class Book extends React.Component {
  render() {
    var style= {
      backgroundColor: this.props.taken ? 'red' : 'green'
    };
    return (
      <td style={style}>Book{this.props.book_id}</td>
    );
  }
}

2 个答案:

答案 0 :(得分:1)

嗯,您需要更新示例代码才能在一个架子上更改图书。在您的示例中,每个书架总是具有相同的5本书,具有相同的ID。因此,在此设置中,您无法仅在一个书架上更改书籍。

此外,如果您从祖父母那里传递taken参数,则它是道具,而不是州。
您可以使用道具并将其转换为初始状态,但这只会意味着之后会有一些用户交互来操纵状态。

最后,在反应中使用映射索引作为key并不是一个好主意。最好使用唯一的ID。

更新后的代码如下所示:

Layout.js

export default class Layout extends React.Component {
  render() {
    // library is an array of bookshelf objects
    // each bookshelf object contains book objects
    // fifth book on second shelf is taken
    var library = [
      { id: "shelf1", books: [
        { id: "book11", taken: false },
        { id: "book12", taken: false },
        { id: "book13", taken: false },
        { id: "book14", taken: false },
        { id: "book15", taken: false }]
      },
      { id: "shelf2", books: [
        { id: "book21", taken: false },
        { id: "book22", taken: false },
        { id: "book23", taken: false },
        { id: "book24", taken: false },
        { id: "book25", taken: true }]
      }
    ];
    var bookshelves = library.map((bookshelf) => 
      <Bookshelf key={bookshelf.id} 
                 bookshelf_id={bookshelf.id} 
                 books={bookshelf.books}/>);
    return (
      <div>
        {bookshelves}
      </div>
    );
  }
}

Bookshelf.js

export default class Bookshelf extends React.Component {
  render() {
    var books = this.props.books.map((book) => 
      <Book key={book.id} book_id={book.id} taken={book.taken}/>);
    return (
      <table>
      <h1>{this.props.bookshelf_id}</h1>
        {books}
      </table>
    );
  }
}

Book.js

export default class Book extends React.Component {
  // put initial taken parameter in state
  getInitialState() {
    return { taken: this.props.taken }
  },
  render() {
    var style= {
      backgroundColor: this.state.taken ? 'red' : 'green'
    };
    return (
      <td style={style}>Book{this.props.book_id}</td>
    );
  }
}

答案 1 :(得分:0)

确定道具/状态应该存在的位置可能是使用React最具挑战性和最有趣的部分。作为哲学的指南,我会仔细研究Thinking In React指南。

但要简单回答你的问题;

数据应始终作为需要访问它的最高阶组件中的状态存在。因此,对于此示例,有关您图书的实际数据应作为Layouts组件上的状态元素存在。

数据以道具的形式传递给儿童,并且被较低级别视为不可变。即,您的书架和书籍组件将无法直接修改他们拥有的书籍数据。相反,他们将利用道具回调到Layouts,它将对其状态中的数据执行操作,因此,将更新其子项的道具,从而导致适当的重新渲染。

React中的数据是单向的,从父级到子级。儿童成分应该永远不需要询问他们父母的任何事情。父母应该提供孩子们作为道具所需的一切。