首页 > 解决方案 > 将数据子传递给reactjs中的父功能组件

问题描述

如何在反应中将数据从子功能组件传递到父功能组件。我想要从父组件传递到子组件的 vehicle.drive 数据。但是子组件获取我想要传递给父组件的特定数据条目。我在子组件中发表了评论,显示了我希望在哪里恢复数据。

父组件:

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import GridList from '@material-ui/core/GridList';
import GridListTile from '@material-ui/core/GridListTile';
import FolderOpenIcon from '@material-ui/icons/FolderOpen';
import Vehicle from "./vehicle";

const vehicleData = [
    {
        name: "COMET",
        agency: "Agency 1",
        drive: "https://drive.google.com
    },
    {
        name: "STAR",
        agency: "Agency 2",
        drive: "https://drive.google.com
    }
];
const useStyles = makeStyles((theme) => ({
    root: {
        display: 'flex',
        flexWrap: 'wrap',
        justifyContent: 'flex-start',
        overflow: 'hidden',
        backgroundColor: theme.palette.background.paper,
        marginTop: '1em'
    },
    gridList: {
        flexWrap: 'nowrap',
        // Promote the list into his own layer on Chrome. This cost memory but helps keeping high FPS.
        transform: 'translateZ(0)',
    },
    title: {
        color: theme.palette.primary.light,
    },
    titleBar: {
        background:
            'linear-gradient(to top, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.3) 70%, rgba(0,0,0,0) 100%)'
    },
}));

const setDataReceivedFromChild=(index)=>{ 
        console.log(index);
}
const VehicleList = () => {
    const classes = useStyles();
    const drive = React.useState("");
    return (
        <div className={classes.root}>
            <GridList className={classes.gridList} cols={10}>
                {vehicleData.map((vehicle) => (
                    <GridListTile key={FolderOpenIcon} style={{width: '30rem'}}>
                        <Vehicle vehicle={vehicle} receiveDataFromChild={this.setDataReceivedFromChild}/>
                    </GridListTile>
                ))}
            </GridList>
        </div>
    );
}

export default VehicleList;

子组件:

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import Grid from '@material-ui/core/Grid';
import Button from '@material-ui/core/Button';
import FolderOpenIcon from '@material-ui/icons/FolderOpen';

const useStyles = makeStyles((theme) => ({
    root: {
        margin: '0.5em',
        display: 'flex',
        flexWrap: 'wrap',
        '& > *': {
          margin: theme.spacing(1.2),
          width: theme.spacing(15),
          height: theme.spacing(18),
        },
    },
}));
const sendDataToParent=(index)=>{
   this.receiveDataFromChild(index);
}
const Vehicle = ({vehicle}) => {
    const classes = useStyles();
    const driveURL = React.useState("");

    return (
        
        <Paper className={classes.root} elevation={3}>
            <Grid container spacing={2}>
                <Grid item>
                    <Typography style={{ fontSize: '20px'}} className={classes.title} color="textSecondary" gutterBottom>
                      {vehicle.name}
                    </Typography>
                    <Typography variant="h5" component="h2">
                      {vehicle.agency}
                    </Typography>
                </Grid>
                <CardActions>
                <Button
                    onClick={()=>{this.sendDataToParent(vehicle.drive)}} //this is where it needs to be passed
                    size="small"
                    color="secondary"
                    startIcon={<FolderOpenIcon />}
                    style={{fontWeight:"bold"}}
                  >
                    Drive
                </Button>
                    <Button
                        color="secondary"
                        size="small"
                        className={classes.button}
                        startIcon={<CallIcon />}
                        style={{fontWeight:"bold"}}
                    >
                        Data Calls
                    </Button>
                    <Button
                        size="small"
                        color="secondary"
                        className={classes.button}
                        startIcon={<DateRangeIcon />}
                        style={{fontWeight:"bold"}}
                    >
                        Pipeline
                    </Button>
                </CardActions>
            </Grid>
        </Paper>
    );
}

export default Vehicle;

import React, {Component, Fragment, useState, useEffect} from 'react';
import { withRouter } from 'react-router-dom'
import Grid from '@material-ui/core/Grid';
import Box from "@material-ui/core/Box";
import CardsContainer from "../components/notifications/cards-container";
import VehicleList from "../components/vehicles/vehicles-list";
import DriveEmbedder from "../components/drive/drive-embedder";

父组件的父组件

class HomePage extends Component {

    constructor(props) {
        super(props);

        this.state = {
            currentUser: {name: 'Surpol', picture: undefined},
            showNewNotification: false,
            driveURL: '',
            
        };
    }

   
    getChildData = (id) => {
        console.log(id);
        this.setState({ //this is obviously wrong to do 
           driveURL: id,
        });

    }

    render() {          
        return (
            <Fragment>
                    <Grid container spacing={1}>
                        <Grid item xl={9} lg={9} md={12}>

                            <Box style={{width: '100%', marginBottom: '1rem'}}>
                                <VehicleList getChildData = {this.getChildData}/> //I want to get the data that was retrieved in the previous parent component here, and then change the this.state.driveURL to equal this
                            </Box>

                            <Box style={{width: '100%', height: '60vh', border: '2px', borderColor: 'black', marginTop: '1rem'}}>
                                <DriveEmbedder url={this.state.driveURL} />
                            </Box>
                        </Grid>
                    </Grid>

            </Fragment>
        );
    }
}

export default (withRouter(HomePage));

标签: reactjs

解决方案


假设状态drive需要存在于 Parent 和 Child 中。然后在父级中定义它并创建一个负责更改此状态的回调函数setDrive

通常,必须在使用或更改此状态的组件之间最接近的共同祖先处定义状态,这称为Lifting State Up。在你的情况下,是这样的(完整的演示):

家长:

const VehicleList = () => {
  const classes = useStyles();
  const [drive, setDrive] = React.useState(null); // the lifted state

  const sendDataToParent = (index) => { // the callback. Use a better name
    console.log(index);
    setDrive(index);
  };

  return (
    <div className={classes.root}>
      {vehicleData.map((vehicle) => (
        <div
          key={vehicle.name}
          style={{
            width: "20rem",
            border: vehicle.name === drive ? "1px solid red" : null
          }}
        >
          <Vehicle vehicle={vehicle} sendDataToParent={sendDataToParent} />
        </div>
      ))}
    </div>
  );
};

孩子:

const Vehicle = ({ vehicle, sendDataToParent }) => {
  const classes = useStyles();
  const [showDriveAction, setShowDriveAction] = React.useState(false);
  const driveURL = React.useState("");

  return (
    <Paper className={classes.root} elevation={3}>
      <Grid container spacing={2}>
        {/* ... */}
        <CardActions>
          <Button
            onClick={() => {
              sendDataToParent(vehicle.name);
            }} //this is where it needs to be passed
            size="small"
            color="secondary"
            startIcon={<FolderOpenIcon />}
            style={{ fontWeight: "bold" }}
          >
          {/* ... */}
        </CardActions>
      </Grid>
    </Paper>
  );
};

推荐阅读