联系服务时反应设置消息

时间:2017-11-07 03:20:24

标签: reactjs

我有一个react组件,我想显示一条消息,告诉用户它正在与服务进行通信,并在完成后删除消息。我似乎无法让它发挥作用。当我点击按钮时,所有孩子都会显示," loading ..."并且消息永远不会消失

class RecipeList extends Component {
    constructor() {
        super();
        this.state = { Names: [], loadingMessage: "" };
    }

    componentDidMount() {
        const settings = appConfig;
        fetch(settings.RestServerLocation + "/Api/recipe", {
            headers : { 
                'Content-Type': 'application/json',
                'Accept': 'application/json'
               }    
        })
            .then(result => {
                return result.json();
            })
            .then(data => {
                this.setState({ Names: data })
            });
    }

    render() {
        const recipeListItems = this.state.Names.map((recipeName) =>

            <li key={recipeName.Name.toString()}className="row" item={recipeName.Name}>
                <Col xs="12" md="6">{recipeName.Name}</Col>
                <Col xs="12" md="6">{this.state.loadingMessage}
                    <Button size="sm" onClick={() => this.props.viewclick(this, recipeName.Id)}>View recipe</Button>
                </Col>
            </li>
        );
        return (
            <div>
                <Card className="card-modified">
                    <CardHeader>Recipe List</CardHeader>
                    <CardBody>
                        <CardText>
                            <ul>
                                {recipeListItems}
                            </ul>
                        </CardText>
                    </CardBody>
                </Card>
            </div>
        );
    }
};

它的父母有代码

recipeListViewClickHandler = (w, id) => {
    const settings = appConfig;
    w.state.loadingMessage = "loading..."
    fetch(settings.RestServerLocation + "/Api/recipe/" + id)
      .then(result => {
        return result.json();
      })
      .then(data => {
        console.log(data);
        //const foo = data;
        this.setState({ Recipe: data })
        w.state.loadingMessage = "complete";
      }
      )
      .catch(e => {
        console.log(e)
        return e;
      });
  }

以及渲染中的此代码

<Col xs="12" lg="8"><RecipeList addclick={this.recipeListAddClickHandler} viewclick={this.recipeListViewClickHandler} />

2 个答案:

答案 0 :(得分:1)

在父级中设置子组件的状态是一种反模式,但是通过调用w.state.loadingMessage,您不会告诉组件更新,因此它永远不会知道改变。 setState()函数将在告知组件更新时设置state属性。你可能能够逃脱w.setState({loadingMessage: "complete"}),但你真的不应该这样做。

如果要设置来自父级的加载消息,请将状态设置为父级(this.setState({loadingMessage: "complete"}))而不是子级,然后将其作为子级传递给子级。一个财产而不是。

render() {
  const {loadingMessage} = this.state;

  return <Col xs="12" lg="8">
    <RecipeList
      addclick={this.recipeListAddClickHandler}
      viewclick={this.recipeListViewClickHandler}
      loadingMessage={loadingMessage}
    />
  </Col>;
}

修改 根据你的评论,我已经意识到你的方式有点倒退。在列表组件中,您将从API中获取集合,但是从父项获取实例数据。你在这里缺少一个子组件。 ListItem应该被提取为一个组件,并且可以为自己管理状态:)

class RecipeListItem extends Component {
  constructor() {
    super();
    this.setState({loadingMessage: ""});
  }

  handleClick = () => {
    const {recipeName} = this.props;
    const settings = appConfig;

    this.setState({loadingMessage: "loading..."});
    fetch(`${settings.RestServerLocation}/Api/recipe/${recipeName.id}`)
      .then(result => result.json())
      .then(data => {
        console.log(data);
        this.setState({loadingMessage: "complete"});
      })
      .catch(e => {
        console.log(e);
        this.setState({loadingMessage: "ERROR"});
        return e;
      });
  }

  render() {
    const {recipeName} = this.props;

    return <li
      key={recipeName.Name.toString()}
      className="row"
      item={recipeName.Name}
    >
      <Col xs="12" md="6">{recipeName.Name}</Col>
      <Col xs="12" md="6">
        {this.state.loadingMessage}
        <Button size="sm" onClick={this.handleClick}>
          View recipe
        </Button>
      </Col>
    </li>;
  }
}

然后,在List组件中,只使用子项:

render() {
    const recipeListItems = this.state.Names.map((recipeName) =>
        <RecipeListItem recipeName={recipeName} />
    );

    return (
        <div>
            <Card className="card-modified">
                <CardHeader>Recipe List</CardHeader>
                <CardBody>
                    <CardText>
                        <ul>
                            {recipeListItems}
                        </ul>
                    </CardText>
                </CardBody>
            </Card>
        </div>
    );
}

答案 1 :(得分:0)

您正在从父组件内的函数设置子组件的state。在React中,组件的state不应该变异,而应该只使用this.setState方法设置。因此,您可以将代码更改为

w.setState({loadingMessage:'complete'});
....
w.setState({loadingMessage:'loading...'});

并检查它是否有效。

但我建议您重构代码,以便

  1. 仅在子组件
  2. 内修改了子级state
  3. 父项的stateprops一起流入子组件以及任何必要的操作(函数)。
  4. 这些操作允许孩子将任何必要的数据发送回父母
  5. 如果不查看更多代码,就不可能进行这样的重构。