从反应中的另一个组件访问状态

时间:2019-02-24 17:02:03

标签: javascript reactjs

仅学习React并遇到问题。我有一个选择器,可以选择车辆的年份/品牌/型号。但是,如果要更改年份,我希望它重置品牌和型号,或者如果更改品牌,我只是希望重置型号,以便将这些选项状态设置为null,从而取消选中ui。

但是,问题是我不知道如何使其他人可以使用组件的状态。我认为解决方案可能像使用year的onChange函数一样简单,然后将使用make / model的状态并将其重置为null,尽管没有year.js无法知道其他2个状态,这是不可能的。 / p>

希望您能理解我在说什么。这是代码。 Year.js

import React, { Component } from 'react';
import '../CSS/App.css';

const vehicleYear = [
    {id:1,label:"2019",href:"#"},
    {id:2,label:"2018",href:"#"},
    {id:3,label:"2017",href:"#"},
    {id:4,label:"2016",href:"#"},
    {id:5,label:"2015",href:"#"},
    {id:6,label:"2014",href:"#"}
];

class Year extends Component {
    constructor(props){
        super(props);

        this.state = {
            year: null,
        }
    }

        createYearList = () => {
            let listItems = [];

            for (let i = 0; i < vehicleYear.length; i++) {
                listItems.push(
                    <li className={`list ${this.state.year === vehicleYear[i].id ? "active" : ""}`} onClick={(e) => {
                        this.yearClick(e, vehicleYear[i].id, vehicleYear[i].label)
                    }}>
                        <a href={vehicleYear[i].href}>{vehicleYear[i].label}</a>
                    </li>
                );
            }
            return listItems;
        };

        yearClick = (e, id, label) => {
            let state = this.state;
            state.year = id;
            this.setState(state);

            console.log(this.state);
            console.log(this.props.year);
        };

        render() {
            return (
                <div>
                    {this.createYearList()}
                </div>
            )
        }

}

export default Year;

Make.js

import React, { Component } from 'react';
import '../CSS/App.css';

const vehicleMake = [
    {id:1,label:"POLARIS",href:"#"},
    {id:2,label:"CAN_AM",href:"#"},
    {id:3,label:"YAMAHA",href:"#"},
    {id:4,label:"SUZUKI",href:"#"},
    {id:5,label:"ARCTIC-CAT",href:"#"}
];

class Make extends Component {
    constructor(props){
        super(props);

        this.state = {
            make: null
        }
    }

    createMakeList = () => {
        let listItems = [];

        for(let i = 0; i < vehicleMake.length; i++){
            listItems.push(
                <li className={`list ${this.state.make === vehicleMake[i].id ? "active" : ""}`} onClick={(e)=>{this.makeClick(e, vehicleMake[i].id, vehicleMake[i].label)}}>
                    <a href={vehicleMake[i].href}>{vehicleMake[i].label}</a>
                </li>
            );
        }
        return listItems;
    };

    makeClick = (e, id, label) => {
        console.log(id, label);
        let state = this.state;
        state.make = id;
        this.setState(state);
        console.log(state.make);
    };

    render() {
        return (
            <div>
                {this.createMakeList()}
            </div>
        )
    }

}

export default Make;

Model.js

import React, { Component } from 'react';
import '../CSS/App.css';

const vehicleModel = [
    {id:1,label:"RZR 570",href:"#"},
    {id:2,label:"RZR 900",href:"#"},
    {id:3,label:"RZR S 900",href:"#"},
    {id:4,label:"RZR S 1000",href:"#"},
    {id:5,label:"RZR S 1000 TURBO",href:"#"}
];

class Model extends Component {
    constructor(props){
        super(props);

        this.state = {
            model: null
        }
    }

    createModelList = () => {
        let listItems = [];

        for(let i = 0; i < vehicleModel.length; i++){
            listItems.push(
                <li className={`list ${this.state.model === vehicleModel[i].id ? "active" : ""}`} onClick={(e)=>{this.modelClick(e, vehicleModel[i].id, vehicleModel[i].label)}}>
                    <a href={vehicleModel[i].href}>{vehicleModel[i].label}</a>
                </li>
            );
        }
        return listItems;
    };

    modelClick = (e, id, label) => {
        console.log(id, label);
        let state = this.state;
        state.model = id;
        this.setState(state);
    };

    render() {
        return (
            <div>
                {this.createModelList()}
            </div>
        )
    }

}

export default Model;

这是主要的App.js

import React, { Component } from 'react';
import './CSS/App.css';
import { Container, Row, Col } from 'reactstrap';
import rzrPic from './Media/rzr-xp-1000-eps-trails-rocks-media-location-1-xxs.jpg';
import camsoT4S from './Media/camso-atv-t4s.jpg';
import Year from './Components/Year';
import Make from './Components/Make';
import Model from './Components/Model';

class App extends Component {

    render() {

    return (
      <div className="App">
          <Container fluid="true">
              <Row>
                  <Col xs="3" className="categories">
                      <div>
                        <span className="categoryHeader">
                            <h2 className="categoryHeading">
                                VEHICLE YEAR
                            </h2>
                        </span>
                        <div className="categoryList">
                            <ul>
                                <Year/>
                            </ul>
                        </div>
                      </div>
                      <div>
                        <span className="categoryHeader">
                            <h2 className="categoryHeading">
                                VEHICLE MAKE
                            </h2>
                        </span>
                          <div className="categoryList">
                              <ul>
                                  <Make/>
                              </ul>
                          </div>
                      </div>
                      <div>
                        <span className="categoryHeader">
                            <h2 className="categoryHeading">
                                VEHICLE MODEL
                            </h2>
                        </span>
                          <div className="categoryList">
                              <ul>
                                  <Model/>
                              </ul>
                          </div>
                      </div>
                  </Col>
                  <Col xs="6" className="fill">
                      <img src={rzrPic} alt="rzr xp 1000"/>
                  </Col>
                  <Col xs="3" className="categories">
                      <span className="categoryHeader2">
                          <h2 className="categoryHeading">
                              AVAILABLE TRACKS
                          </h2>
                      </span>
                      <div className="Track">
                          <img src={camsoT4S} alt="Camso T4S Tracks"/>
                          <div className="TrackInfo">
                              <h3>CAMSO T4S - 4 SEASON</h3>
                              <p>Starting at $3,999.00</p>
                              <span>
                                  ADD TO CART
                              </span>
                          </div>
                      </div>
                      <div className="Track">
                          <div className="TrackInfo">
                              <h3>CAMSO T4S - 4 SEASON</h3>
                              <p>Starting at $3,999.00</p>
                              <p className="select">SELECT</p>
                          </div>
                      </div>
                  </Col>
              </Row>
          </Container>
      </div>
    );
  }
}

export default App;

在此先感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

与其在每个组件中存储选定的年份/品牌/型号,不如将它们存储在父级App中。然后,您将在App组件中处理重置逻辑。

以下是重构代码的方法:

import React, { Component } from "react";
import "../CSS/App.css";

// The list of years is now passed as props
//
// const vehicleYear = [];

class Year extends Component {
  // You dont need the constructor anymore as the component
  // doesn't have a state to initialize
  //
  // constructor(props) {}

  createYearList = () => {
    // Use the year list passed as a prop from the parent
    const { vehicleYear } = this.props;

    let listItems = [];

    for (let i = 0; i < vehicleYear.length; i++) {
      listItems.push(
        <li
          className={`list ${
            this.state.year === vehicleYear[i].id ? "active" : ""
          }`}
          onClick={e => {
            this.yearClick(e, vehicleYear[i].id, vehicleYear[i].label);
          }}
        >
          <a href={vehicleYear[i].href}>{vehicleYear[i].label}</a>
        </li>
      );
    }
    return listItems;
  };

  yearClick = (e, id, label) => {
    // Call the onClick function passed as a prop from the parent
    this.props.onClick(e, id, label);
  };

  render() {
    return <div>{this.createYearList()}</div>;
  }
}

export default Year;

我只修改了Year组件,因为MakeModel组件具有相同的结构。我待会儿再讲。

这是在Year中使用App的方法:

import React, { Component } from 'react';
// import ...

// Define the list of years
const vehicleYear = [
  {id:1,label:"2019",href:"#"},
  {id:2,label:"2018",href:"#"},
  {id:3,label:"2017",href:"#"},
  {id:4,label:"2016",href:"#"},
  {id:5,label:"2015",href:"#"},
  {id:6,label:"2014",href:"#"}
];

class App extends Component {

    constructor(props){
        super(props);

        // Initialise the state of the App component
        this.state = {
            year: null,
        }
    }

    // Move the click handler from the Year component to its parent component
    yearClick = (e, id, label) => {
      this.setState({
        year: id
      });
    };

    render() {
      return (
        <div className="App">
            <Container fluid="true">
                <Row>
                    <Col xs="3" className="categories">
                        <div>
                          <span className="categoryHeader">
                              <h2 className="categoryHeading">
                                  VEHICLE YEAR
                              </h2>
                          </span>
                          <div className="categoryList">
                              <ul>
                                  {/* Pass the list of years, the selected year and the handler to 
                                  select a year to the Year component */}
                                  <Year vehicleYear={vehicleYear} selectedYear={this.state.year} onClick={this.yearClick} />
                              </ul>
                          </div>
                        </div>
                        ...
                </Row>
            </Container>
        </div>
      );
  }
}

export default App;

现在,您已完全控制了Year,并由App组件处理了逻辑。如果要重置选定的年份,只需在App组件中创建并调用这样的函数:

resetYear = () => {
  this.setState({
    year: null
  });
};

奖金:重构

您可以将YearMakeModel组件重新引用为一个可重用组件,因为它们的结构完全相同。这是从中提取的ListComponent

// The list components takes three arguments:
// - itemsList: items to be displayed
// - selectedItemId: the id of the selected item
// - onSelect: a function to call when an item is selected

class ListComponent extends Component {
  render() {
    const { itemsList, selectedItemId, onSelect } = this.props;

    return (
      <div>
        {itemsList.map(item => (
          <li
            className={`list ${selectedItemId === item.id ? "active" : ""}`}
            onClick={e => {
              onSelect(e, item.id, item.label);
            }}
          >
            <a href={item.href}>{item.label}</a>
          </li>
        ))}
      </div>
    );
  }
}

export default ListComponent;

您可以像这样使用它:

<div>
  <span className="categoryHeader">
      <h2 className="categoryHeading">
          VEHICLE YEAR
      </h2>
  </span>
  <div className="categoryList">
      <ul>
          <ListComponent onSelect={this.selectYear} itemsList={vehicleYear} selectedItemId={this.state.year}/>
      </ul>
  </div>
</div>
<div>
  <span className="categoryHeader">
      <h2 className="categoryHeading">
          VEHICLE MAKE
      </h2>
  </span>
    <div className="categoryList">
        <ul>
            <ListComponent onSelect={this.selectMake} itemsList={vehicleMake} selectedItemId={this.state.make}/>
        </ul>
    </div>
</div>
<div>
  <span className="categoryHeader">
      <h2 className="categoryHeading">
          VEHICLE MODEL
      </h2>
  </span>
    <div className="categoryList">
        <ul>
            <ListComponent onSelect={this.selectModel} itemsList={vehicleModel} selectedItemId={this.state.model}/>
        </ul>
    </div>
</div>

答案 1 :(得分:0)

在这种情况下,最简单的解决方案是将您的状态保留在父级中,或者将组件临时创建为组件的父级,然后简单地传递一个onChangeYear属性,例如更改状态你的父母

import React, { Component } from 'react';
import './CSS/App.css';
import { Container, Row, Col } from 'reactstrap';
import rzrPic from './Media/rzr-xp-1000-eps-trails-rocks-media-location-1-xxs.jpg';
import camsoT4S from './Media/camso-atv-t4s.jpg';
import Year from './Components/Year';
import Make from './Components/Make';
import Model from './Components/Model';

class App extends Component {
    contructor(props) {
       super(props);
       this.state = { year: "" }
    }


    render() {

    return (
      <div className="App">
          <Container fluid="true">
              <Row>
                  <Col xs="3" className="categories">
                      <div>
                        <span className="categoryHeader">
                            <h2 className="categoryHeading">
                                VEHICLE YEAR
                            </h2>
                        </span>
                        <div className="categoryList">
                            <ul>
                                <Year onChangeYear={(year) => {this.setState({year})/>
                            </ul>
                        </div>
                      </div>
                      <div>
                        <span className="categoryHeader">
                            <h2 className="categoryHeading">
                                VEHICLE MAKE
                            </h2>
                        </span>
                          <div className="categoryList">
                              <ul>
                                  <Make/>
                              </ul>
                          </div>
                      </div>
                      <div>
                        <span className="categoryHeader">
                            <h2 className="categoryHeading">
                                VEHICLE MODEL
                            </h2>
                        </span>
                          <div className="categoryList">
                              <ul>
                                  <Model/>
                              </ul>
                          </div>
                      </div>
                  </Col>
                  <Col xs="6" className="fill">
                      <img src={rzrPic} alt="rzr xp 1000"/>
                  </Col>
                  <Col xs="3" className="categories">
                      <span className="categoryHeader2">
                          <h2 className="categoryHeading">
                              AVAILABLE TRACKS
                          </h2>
                      </span>
                      <div className="Track">
                          <img src={camsoT4S} alt="Camso T4S Tracks"/>
                          <div className="TrackInfo">
                              <h3>CAMSO T4S - 4 SEASON</h3>
                              <p>Starting at $3,999.00</p>
                              <span>
                                  ADD TO CART
                              </span>
                          </div>
                      </div>
                      <div className="Track">
                          <div className="TrackInfo">
                              <h3>CAMSO T4S - 4 SEASON</h3>
                              <p>Starting at $3,999.00</p>
                              <p className="select">SELECT</p>
                          </div>
                      </div>
                  </Col>
              </Row>
          </Container>
      </div>
    );
  }
}

export default App;

如果您发现自己的Web应用程序中有很多组件,我会考虑集成Redux以全局处理状态https://redux.js.org/introduction/getting-started