反应 - 在兄弟姐妹之间传递状态?

时间:2016-12-07 22:25:40

标签: javascript reactjs meteor

基本上是React的新手,我对如何在组件之间正确传递状态感到困惑。我发现了一个类似的问题React – the right way to pass form element state to sibling/parent elements? 但是我想知道你是否可以给我一个特定的答案来解释下面的代码。

目前,该应用程序的结构包括:

  • 父组件 - App
  • 2个孩子:SearchBarRecipesList

目标是在我的Meteor集合上进行异步搜索,并仅显示与搜索词匹配的recipes

现在,我只是在我的Meteor系列中展示所有食谱。 我创建了一个名为SearchBar的有状态组件,它将输入值保存为this.state.term。我的想法是将状态传递给RecipesList,但我不确定这是否正确。或者,我让App处理状态并将其传递给孩子。我相信这是一种非常常见的情况,你是怎么做到的?

App

class App extends Component {

render( ) {
    return (
        <div>
            <Navbar/>
            <SearchBar/>
            <RecipesList/>
        </div>
    );
}
}

SearchBar

export default class SearchBar extends Component {

constructor( props ) {
    super( props );

    this.state = {
        term: ''
    };
}

onInputChange( term ) {
    this.setState({ term });
}

render( ) {
    return (
        <div className=" container-fluid search-bar">
            <input value={this.state.term} onChange={event => this.onInputChange(event.target.value.substr( 0, 50 ))}/>
            Value: {this.state.term}
        </div>
    );
}

}

RecipesList

const PER_CLICK = 5;

class RecipesList extends Component {

componentWillMount( ) {
    this.click = 1;
}

handleButtonClick( ) {
    Meteor.subscribe('recipes', PER_CLICK * ( this.click + 1 ));
    this.click++;
}

renderList( ) {
    return this.props.recipes.map(recipe => {
        return (
            <div key={recipe._id} className="thumbnail">
                <img src={recipe.image} alt="recipes snapshot"/>
                <div className="caption">
                    <h2 className="text-center">{recipe.recipeName}</h2>
                </div>
            </div>
        );
    });
}

render( ) {
    return (
        <ul className="list-group">
            {this.renderList( )}
            <div className="container-fluid">
                <button onClick={this.handleButtonClick.bind( this )} className="btn btn-default">More</button>
            </div>
        </ul>
    );
}
}

// Create Container and subscribe to `recipes` collection
export default createContainer( ( ) => {
Meteor.subscribe( 'recipes', PER_CLICK );
return {recipes: Recipes.find({ }).fetch( )};
}, RecipesList );

2 个答案:

答案 0 :(得分:2)

App

class App extends Component {
  constructor(props, ctx){
    super(props, ctx)

    this.state = {
      searchQuery: ''
    }

    this.searchInputChange = this.searchInputChange.bind(this)
  }

  searchInputChange(event) {
    this.setState({
      searchQuery: event.target.value.substr( 0, 50 )
    })
  }

  render( ) {
    const { searchQuery } = this.state
    return (
      <div>
        <Navbar/>
        <SearchBar onChange={this.searchInputChange} value={searchQuery}/>
        <RecipesList searchQuery={searchQuery}/>
      </div>
    )
  }
}

App组件处理状态,然后通过props.searchQuery向RecipesList提供搜索术语作为道具传递给子项。

searchInputChange处理程序作为道具传递给SearchBar

SearchBar

export default const SearchBar = ({value, onChange}) => (
  <div className=" container-fluid search-bar">
    <input value={value} onChange={onChange}/>
    Value: {value}
  </div>
)

由于SearchBar委托状态到父组件,我们可以使用无状态反应组件,因为我们只需要来自props的信息来呈现它。

一般来说,最好让logicalstatefulcontroller组件处理状态和逻辑,然后该组件将状态和方法传递给{{1 }}或presentational组件,用于处理用户看到和与之交互的内容。

答案 1 :(得分:0)

将状态term定义到App组件中。 还要编写handleInput函数并将其作为porps

传递给SearchBar组件
handleInput(val) {
this.setState({
    term: val,
});
}

当输入搜索栏中的某些内容(onKeyUp)时,添加侦听器handleInput。

同时创建<RecipesList searchQuery={this.state.term}/>

现在在渲染功能RecipesList中过滤掉你想要从列表中显示的食谱