簡體   English   中英

從反應中的另一個組件訪問狀態

[英]Accessing state from another component in react

只是學習React並遇到問題。 我有一個選擇器,可以選擇車輛的年份/品牌/型號。 但是,我希望它在更改年份時重置品牌和型號,或者在更改品牌時僅重置型號,以便將這些選項狀態重新設置為null,從而取消選中ui。

但是,問題是我不知道如何使其他人可以使用組件的狀態。 我認為解決方案可能像使用year的onChange函數一樣簡單,然后它將獲取make / model的狀態並重置為null,盡管沒有year.js無法知道其他2個狀態,這是不可能的...

希望你理解我在說什么。 這是代碼。 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;

在此先感謝您的幫助!

與其將所選的年份/品牌/型號存儲在每個組件中,不如將它們存儲在父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組件具有相同的結構。 我稍后再講。

這是在App使用Year的方法:

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提取的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>

最簡單的解決方案是在這種情況下將您的狀態保留在父級中,或者在組件中臨時創建一個組件作為父級,然后簡單地傳遞一個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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM