如何在搜索输入上使用React上下文并与其他组件共享输入?



我试图避免使用Redux,并希望将搜索结果共享到标题外的组件。我的标题出现在每个页面上,数据在Lessons组件内。我想在标题中搜索并将结果转移到Lessons组件和Students组件。有什么线索吗?

下面是我的代码。

app.js

import "./App.css";
import Lessons from "./components/Lessons";
import LoadingHOC from "./components/LoadingHOC";
import React, { useEffect, useState } from "react";
import { Route, BrowserRouter as Router, Switch, matchPath } from "react-router-dom";
import { ThemeProvider } from "@material-ui/core/styles";
import Header from "./components/Header";
import Footer from "./components/Footer";
import UpdateForm from "./components/UpdateForm";
import Register from "./components/Register";
import CreateLesson from "./components/CreateLesson";
import DeleteLesson from "./components/DeleteLesson";
import Students from "./components/Students";
import UpdateStudent from "./components/UpdateStudent"
import Login from "./components/Login";
import AddStudent from "./components/AddStudent";
import DeleteStudent  from "./components/DeleteStudent";
import theme from "./theme";
function App() {
// const LessonsLoading = LoadingHOC(Lessons);
// // const StudentsLoading = LoadingHOC(Students);
/
// };

const [appState, setAppState] = useState({ loading: false, lessons: [] });
useEffect(() => {
console.log("debug app state");
setAppState({ loading: true });
// const apiUrl = "http://127.0.0.1:8000/api/";
// fetch(apiUrl)
//   .then((data) => data.json())
//   .then((lessons) => {
//     debugger;
//     setAppState({ loading: false, lessons: lessons });
//     // console.log(lessons);
//   });
}, []);
// console.log('debug loading', appState.loading)
// console.log('debug loading', appState.lessons)


return (
// console.log('debug lessons', appState.lessons),
// <div className="app">
//   <LessonsLoading isLoading={appState.loading} lessons={appState.lessons}/>
//   {/* <StudentsLoading isLoading={appState.loading} students={appState.students}/> */}
// </div>
<ThemeProvider theme={theme}>
{/* <Router> */}
<React.StrictMode>
<Header />
{/* <LoadingHOC /> */}
<Switch>
{console.log("debug lessons", appState.lessons)}
<Route
exact
path="/"
component={Lessons}
// lessons={appState.lessons}
/>
<Route exact path="/account/register" component={Register} />
<Route exact path="/account/login" component={Login} />
<Route path="/create/" component={CreateLesson} />
<Route path="/delete/" component={DeleteLesson} />

<Route path="/students" component={Students} />
<Route path="/student/:id"  component={UpdateStudent}/>
<Route path="/lessons/:id" component={UpdateForm} />
<Route path="/add_student" component={AddStudent} />


{/* <Route exact path="/" component={App} /> */}
</Switch>
{/* if (!appState.loading) return <Lessons lessons={appState.lessons} />; */}
{/* <Footer /> */}
</React.StrictMode>
{/* </Router> */}
</ThemeProvider>
);
}
export default App;

header.js

import React, { useState, useEffect } from "react";
import {
fade,
makeStyles,
ThemeProvider,
createMuiTheme,
} from "@material-ui/core/styles";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import Typography from "@material-ui/core/Typography";
import IconButton from "@material-ui/core/IconButton";
import MenuIcon from "@material-ui/icons/Menu";
import AccountCircle from "@material-ui/icons/AccountCircle";
import Switch from "@material-ui/core/Switch";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import FormGroup from "@material-ui/core/FormGroup";
import MenuItem from "@material-ui/core/MenuItem";
import Menu from "@material-ui/core/Menu";
import InputBase from "@material-ui/core/InputBase";
import SearchIcon from "@material-ui/icons/Search";
import { Link } from "react-router-dom";
import { useHistory } from "react-router-dom";
import { HistoryTwoTone } from "@material-ui/icons";
import axiosInstance from "./../axios";
import Students from './Students';
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
mainTitle: {
textAlign: "center",
fontWeight: "700",
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
tableTitle: {
textAlign: "center",
},
search: {
position: "relative",
borderRadius: theme.shape.borderRadius,
backgroundColor: fade(theme.palette.common.white, 0.15),
"&:hover": {
backgroundColor: fade(theme.palette.common.white, 0.25),
},
marginLeft: 0,
width: "100%",
[theme.breakpoints.up("sm")]: {
marginLeft: theme.spacing(1),
width: "auto",
},
},
searchIcon: {
padding: theme.spacing(0, 2),
height: "100%",
position: "absolute",
pointerEvents: "none",
display: "flex",
alignItems: "center",
justifyContent: "center",
},
inputRoot: {
color: "inherit",
},
inputInput: {
padding: theme.spacing(1, 1, 1, 0),
// vertical padding + font size from searchIcon
paddingLeft: `calc(1em + ${theme.spacing(4)}px)`,
transition: theme.transitions.create("width"),
width: "100%",
[theme.breakpoints.up("sm")]: {
width: "12ch",
"&:focus": {
width: "20ch",
},
},
},
}));
// Components lib - material, bootstrap, fabric, antd
// css-in-js: styled-components, theme-ui
export default function MenuAppBar() {
const classes = useStyles();
const [auth, setAuth] = React.useState(true);
const [anchorEl, setAnchorEl] = React.useState(null);
const open = Boolean(anchorEl);
// const [studentsData, setStudentsData] = useState("");
// useEffect(() => {
//   axiosInstance.get("/students").then((res) => {
//     setStudentsData({ ...studentsData, students: res.data });
//   });
// }, []);
const handleChange = (event) => {
setAuth(event.target.checked);
};
const handleMenu = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);

};
return (
<div className={classes.root}>
<FormGroup>
<FormControlLabel
control={
<Switch
checked={auth}
onChange={handleChange}
aria-label="login switch"
/>
}
label={auth ? "Logout" : "Login"}
/>
</FormGroup>
<AppBar position="static" color="primary">
<Toolbar>
<IconButton
edge="start"
className={classes.menuButton}
color="inherit"
aria-label="menu"
onClick={handleMenu}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" className={classes.title}>
Anat
</Typography>
{auth && (
<div>
<IconButton
aria-label="account of current user"
aria-controls="menu-appbar"
aria-haspopup="true"
// onClick={handleMenu}
color="inherit"
>
<AccountCircle />
</IconButton>
<Menu
id="menu-appbar"
anchorEl={anchorEl}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
keepMounted
transformOrigin={{
vertical: "top",
horizontal: "right",
}}
open={open}
onClose={handleClose}
>
<MenuItem onClick={handleClose}>Profile</MenuItem>
{/* <Link href={"/students"} studentsList={studentsData.students}> */}
{/* <Link
to={{
pathname: "/students",
state: { studentsList: studentsData.students },
}}
> */}
<MenuItem component={Link} to={'/students'} onClick={handleClose}> Manage Students</MenuItem>
{/* </Link> */}
</Menu>
</div>
)}
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon />
</div>
<InputBase
placeholder="Search…"
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
inputProps={{ "aria-label": "search" }}

/>
</div>
</Toolbar>
</AppBar>
{/* <div><Typography  variant="h6" className="mainTitle">Student Lessons
</Typography>
</div> */}
{/* <div>
<h1 className={classes.tableTitle}>Student Lessons</h1>
</div> */}
</div>
);
}

lessons.js

import React, { useEffect, useState } from "react";
import { makeStyles,fade } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableContainer from "@material-ui/core/TableContainer";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import Paper from "@material-ui/core/Paper";
import UpdateLesson from "./UpdateLesson";
import DeleteLesson from "./DeleteLesson";
import Container from "@material-ui/core/Container";
import Typography from "@material-ui/core/Typography";
import IconButton from "@material-ui/core/IconButton";
import EditIcon from "@material-ui/icons/Edit";
import Link from "@material-ui/core/Link";
import AddIcon from "@material-ui/icons/Add";
import Fab from '@material-ui/core/Fab';
import Grid from '@material-ui/core/Grid';
const useStyles = makeStyles((theme)=>({
table: {
minWidth: "450",
},
tableTitle: {
textAlign: "center",
},
title: {
textAlign: "center",
},
tablerow: {
fontWeight: "bold",
},
root: {
marginTop: theme.spacing(8),
paddingTop: theme.spacing(3),
paddingBottom: theme.spacing(3),

},
fab: {

backgroundColor: fade(theme.palette.primary.light),
// paddingHorizontal: auto,
}
}));

const Lessons = (props) => {
const [lessons, setLessons] = useState([]);
const apiUrl = "http://127.0.0.1:8000/api/";
useEffect(() => {
fetch(apiUrl)
.then((data) => data.json())
.then((lessons) => {
// debugger;
setLessons(lessons || []);
// console.log(lessons);
});
// setAppState({ loading: true });
}, []);
// const { lessons } = props;
console.log({ lessons });
const classes = useStyles();
// if (lessons === null) {
//   return <div>No data</div>;
// }
return (
<React.Fragment>
<Container>
<div>
<h1 className={classes.tableTitle}>Student Lessons</h1>
</div>
<Paper>
<TableContainer component={Paper}>
<Table className={classes?.table} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell className={classes.tablerow}>Id</TableCell>
<TableCell align="right" className={classes.tablerow}>
Student
</TableCell>
<TableCell align="right" className={classes.tablerow}>
Title
</TableCell>
<TableCell align="right" className={classes.tablerow}>
lesson date
</TableCell>
<TableCell align="right" className={classes.tablerow}>
payment
</TableCell>
<TableCell
align="right"
className={classes.tablerow}
></TableCell>
<TableCell
align="right"
className={classes.tablerow}
></TableCell>
</TableRow>
</TableHead>
<TableBody>
{lessons ? (
lessons.map((lesson) => (
<TableRow key={lesson.id}>
<TableCell component="th">{lesson.id}</TableCell>
<TableCell align="right">{lesson.student}</TableCell>
<TableCell align="right">{lesson.title}</TableCell>
<TableCell align="right">{lesson.lesson_date}</TableCell>
<TableCell align="right">{lesson.paid}</TableCell>
<TableCell align="center">
{/* <UpdateLesson lesson={lesson.id} /> */}
<Link href={"/lessons/" + lesson.id}>
<IconButton className={classes.icon}>
<EditIcon />
</IconButton>
</Link>
</TableCell>
<TableCell align="right">
<DeleteLesson lessonId={lesson.id} />
</TableCell>
</TableRow>
))
) : (
<div>No data</div>
)}
</TableBody>
</Table>
</TableContainer>
</Paper>
</Container>
<Container maxWidth="md"  className={classes.root}>
<Grid container spacing={2}>
<Link href={'/create'}>
<Fab className={classes.fab} >
<AddIcon />
</Fab>
</Link>
<Link href={'/students'}>
<Fab className={classes.fab} >
<AddIcon />
</Fab>
</Link>
</Grid>
</Container>

</React.Fragment>
);
};
export default Lessons;

您可以将值存储在变量中…

app.js

import {useRef, useState, useEffect} from 'react'
import Header from './Header';

const app = () => {
const searchRef = useRef(null);
const [searchValue, setSearchValue] = useState(null);
useEffect(() => {
setSearchValue(searchRef.current.value);
})

return (
<Header ref={searchRef} />
)
}

header.js

import {forwardRef} from 'react'

const Header = ({other props like children etc.}, ref) => {

return (
<header>
<input ref={ref} type="text" placeholder="search" />
</header>
)}

const ForwardHeader = forwardRef(Header);

export default ForwardHeader;

从这一点上,你可以做任何你想做的searchValue变量在app.js或转发给一些组件。但是更好的方法是使用简单的context来管理搜索输入

的状态。

最新更新