如何在ReactJS中的组件之间传递数据?

时间:2018-01-29 16:52:08

标签: reactjs

我制作了2个组件: 1)内容(使用fetch()显示数据) 2)分页(每页共5页16个对象)

我制作了两个名为start:0end:16的状态变量。现在,每当用户点击页码时,我想从分页组件向内容组件注入开始和结束状态变量。

将开始和结束变量传递给内容的逻辑如下: 最初结束= 16 * 1(1乘以因为第1页)和start = end-16,即start = 0

结束= 16 * 2(2因为第2页而倍增)和start = end-16,即start = 16

这些开始和结束变量在内容组件的.slice()中传递,以便onClick:  第1页应显示第0至16条 第2页应显示第16至32条,依此类推至第5页

以下是分页代码和内容组件:

content.js:

class Content extends Component {

    constructor(props){
        super(props);
        this.state = {
            matches:[],
            loading:true,
            callmatchinfo: false,
            matchid:''
        };
    }

    componentDidMount(){
        fetch('api/matches')
        .then(res => res.json())
        .then(res => {
      console.log(res)
      this.setState({
        matches:res.slice(this.props.start,this.props.end),  <---add new start and end everytime we click on new page number
        loading:false
      });
    })
    }

  viewstats(matchid){
    this.setState({
        callmatchinfo: true,
        matchid: matchid
    });
  }

  rendermatchinfo(){
    return <Matchinfo matchid={this.state.matchid} />
  }

    renderMatches() {
        return this.state.matches.map(match => {
            return (
                <div className="col-lg-3">
                    <div id="content">
                        <p className="match">MATCH {match.id}</p>
                        <h4>{match.team1}</h4>
                        <p>VS</p>
                        <h4>{match.team2}</h4>
                        <div className="winner">
                            <h3>WINNER</h3>
                            <h4>{match.winner}</h4>
                        </div>
                        <div className="stats">
                            <button type="button" onClick= {()=>{this.viewstats(match.id)}} className="btn btn-success">View Stats</button>
                        </div>
                    </div>
                </div>
            );
        })
    }

    render() {

        if (this.state.loading) {
            return <img src="https://upload.wikimedia.org/wikipedia/commons/b/b1/Loading_icon.gif" />
        }
        else if(this.state.callmatchinfo){
        return <Matchinfo match_id={this.state.matchid} />
        }

    return (
      <div>
          <div className="row">
            {this.renderMatches()}
              </div>
          <div className="row">
            {this.state.callmatchinfo ? this.rendermatchinfo() : ''}
          </div>
      </div>
    );
  }
}

export default Content;

pagination.js:

class Pagination extends Component {

    constructor(props){
        super(props)
        this.state = {
            start:0,
            end:16
        };
    }

    handleClick(){
        this.setState{
            end:getpagenumber()*16,
            start:end-16
        }
    }

    getpagenumber(val){
        return val;
    }


  render() {
    let{start,end} = this.state;

    return (
      <div>
        <Content/>
          <div className="container">                 
              <ul className="pagination">
               <li {this.getpagenumber(1)} onClick={this.handleClick}><a href="#">1</a></li>
                <li {this.getpagenumber(2)} onClick={this.handleClick}><a href="#">2</a></li>
                <li {this.getpagenumber(3)} onClick={this.handleClick}><a href="#">3</a></li>
                <li{this.getpagenumber(4)} onClick={this.handleClick}><a href="#">4</a></li>
                <li{this.getpagenumber(5)} onClick={this.handleClick}><a href="#">5</a></li>
              </ul>
          </div>
      </div>
    );
  }
}

export default Pagination;

屏幕截图显示匹配文章直到16,即end = 16: enter image description here

4 个答案:

答案 0 :(得分:3)

您需要父组件来传达这两个组件,例如:

class ParentComponent extends Component {
    state = {
        start: 0,
        end: 16,
    };

    onChangePagination = (start, end) => {
        this.setState({
            start,
            end,
        });
    };

    render() {
        const { start, end } = this.state;
        return (
            <div>
                <Content start={start} end={end} />
                <Pagination
                    onChange={this.onChangePagination} />
            </div>
        );
    }
}

您需要在分页组件中进行另一项更改,即在值更改时调用onChange回调。

handleClick() {
    const end = (getpagenumber() * 16);
    const start = (end - 16);
    this.setState({
        end: end,
        start: start,
    });
    this.props.onChange(start, end);
}


renderMatches() {
    // Slide matches before looping, props will have the
    // values from the pagination component.
    return this.state.matches.slice(this.props.start, this.props.end)
        .map(match => (
            <div className="col-lg-3">
                <div id="content">
                    <p className="match">MATCH {match.id}</p>
                    <h4>{match.team1}</h4>
                    <p>VS</p>
                    <h4>{match.team2}</h4>
                    <div className="winner">
                        <h3>WINNER</h3>
                        <h4>{match.winner}</h4>
                    </div>
                    <div className="stats">
                        <button
                            type="button"
                            onClick={ () => this.viewstats(match.id) }
                            className="btn btn-success">
                            View Stats</button>
                    </div>
                </div>
            </div>
        )
    );
}

你可能想要从Pagination组件中删除本地状态,你真的不需要它。

答案 1 :(得分:2)

Crysfel拥有最简单的正确解决方案,因为您需要一个父组件来管理数据,并将其作为道具传递给子组件,但还有另一种方法可以更好地适应大型项目。

如果您只是在学习,或者您正在做一些小事,那么一定不要使用它,但Redux是另一种方式。

简而言之,它是一个非常复杂的水桶,可以放置你的状态。现在,不是关注自己状态的组件,而是将非表示状态放在redux存储中,并使用选择器从存储中读取组件。

在您的情况下,当您点击Pagination以改变商店时,您将触发操作,这会导致组件侦听更改的任何数据以进行更新。

答案 2 :(得分:1)

如果您想传递------WebKitFormBoundary62hryFjhCKbptVPz Content-Disposition: form-data; name="MediaInfo" [{"ID":11,"LastName":"Mazzo","FirstName":"Bob","DeviceID":"46","InstanceID":9,"PatientDOB":"1967-05-01","FileName":"Bob and Chris Cardillo.jpg","FileSize":399030,"ExamDate":"1/31/2018","UID":11,"SessionID":"sessionID=cfe351c8-63f8-40b0-909d-d9a5991f6a70"}] ------WebKitFormBoundary62hryFjhCKbptVPz Content-Disposition: form-data; name="files[]"; filename="Bob and Chris Cardillo.jpg" Content-Type: image/jpeg start道具,只需执行以下操作:

end

这应该回答您如何将道具传递给.... render() { let{start,end} = this.state; return ( <div> <Content start={start} end={end} /> ..... 组件的具体问题。

这可能对你有所帮助,但我认为无论如何你应该考虑一些代码重构。

答案 3 :(得分:1)

您需要传递一个将状态从Content更新为Pagination的函数:

将此代码移至Content中的单独函数:

updatePage(start, end) {
    fetch('api/matches')
        .then(res => res.json())
        .then(res => {
            console.log(res)
            this.setState({
                // Add new start and end everytime we click on new page number.
                matches: res.slice(start, end),
                loading: false,
            });
        });
}

然后将其作为道具传递给Pagination

<Pagination updatePage={this.updatePage} />

然后,每次更新Pagination中的页面时,请致电this.props.updatePage

handleClick() {
    const end = this.getpagenumber() * 16;
    const start = end - 16;
    this.setState({
        end,
        start,
    });
    this.props.updatePage(start, end);
}

<强>更新

简单更新到Content只能获取所有数据一次,然后使用props来对每个渲染上的匹配进行切片:

class Content extends Component {

    constructor(props){
        super(props);
        this.state = {
            matches: [],
            loading: true,
            callmatchinfo: false,
            matchid: '',
        };
    }

    componentDidMount() {
        fetch('api/matches')
            .then(res => res.json())
            .then(res => {
                // On mount, load all data and save it in state.
                this.setState({
                    allData: res,
                    loading: false,
                });
            });
    }

    renderMatches() {
        // Here we use slice on all the data and only return
        // 15 matches at a time for rendering.
        return this.state.allData.slice(this.props.start, this.props.end)
            .map(match => (
                <div className="col-lg-3">
                    <div id="content">
                        <p className="match">MATCH {match.id}</p>
                        <h4>{match.team1}</h4>
                        <p>VS</p>
                        <h4>{match.team2}</h4>
                        <div className="winner">
                            <h3>WINNER</h3>
                            <h4>{match.winner}</h4>
                        </div>
                        <div className="stats">
                            <button
                                type="button"
                                onClick={
                                    () => { this.viewstats(match.id) }
                                }
                                className="btn btn-success">
                                View Stats</button>
                        </div>
                    </div>
                </div>
            );
        })
    }

    render() {...}
}

export default Content;