您如何在React中将数据从子功能组件传递到父功能组件。我想要从父组件传递到子组件的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));
答案 0 :(得分:2)
假设状态drive
必须存在于父级和子级中。然后,在父级中定义它,并创建一个负责更改此状态setDrive
的回调函数。
通常,必须在使用或更改此状态的组件之间的最接近的共同祖先中定义状态,这称为Lifting State Up。您的情况是这样的(complete demo):
父母:
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>
);
};