晚上好,所以我试图使用react router params加载我的编辑页面,但出现此错误-无法读取未定义的属性'params'。
在我的编辑页面中,props.match.params._id位于一个单独的Submit组件(在页面顶部)中,而不是导出的组件,然后在App.js上导入该路由。
因此,我相信这是导致我遇到问题的原因,但不确定后,我不确定。
我确实将props传递给了两个组件,我是否需要在某个地方的Edit组件中包含props.match.params._id。
我担心Edit组件有点混乱,可以在外部将这些组件拆分开来吗?
编辑组件
import { MyTestStore } from "./App";
import { AppContext } from './context';
import "react-dropzone-uploader/dist/styles.css";
import Dropzone from "react-dropzone-uploader";
import styled from "styled-components";
import axios from "axios";
import { withRouter } from 'react-router-dom';
// import "./xApp.css";
import { Clear } from "@material-ui/icons";
// import { withRouter } from 'react-router-dom';
// import './style.css';
const MainContainer = styled.main`
grid-area: main;
display: grid;
grid-template-columns: 1fr;
margin: 0;
`;
const MovieForm = styled.form`
display: grid;
grid-template-columns: 1fr 25%;
height: 100vh;
width: 100%;
margin: 0;
`;
const MovieInfo = styled.div`
padding: 80px;
`;
const MoviePosters = styled.div`
background: lightgrey;
padding: 80px 40px;
`;
const HideMe = styled.div`
height: 470px;
overflow-y: auto;
overflow-x: hidden;
background: gainsboro;
border: 1px solid lavender;
`;
const Submit = props => {
const { files, onSubmit } = props;
const { movie, setShowLoading, setMovie } = useContext(AppContext);
const apiUrl = "http://localhost:5000/api/movies/" + props.match.params._id;
useEffect(() => {
setShowLoading(false);
const fetchData = async () => {
const result = await axios(apiUrl);
setMovie(result.data);
console.log(result.data);
setShowLoading(false);
};
fetchData();
}, [apiUrl]);
const handleSubmit = () => {
console.log({ movie });
console.log(files.map(f => f.meta));
const headers = "multipart/form-data";
const formData = new FormData();
formData.set("title", movie.title);
formData.set("date", movie.date);
formData.set("synopsis", movie.synopsis);
formData.set("vID", movie.vID);
formData.set("trailer", movie.trailer);
files.map(fileItem => formData.append("poster", fileItem.file));
console.log(Array.from(formData));
axios
.post(apiUrl, formData, headers)
.then(result => {
setShowLoading(false);
console.log(result);
props.history.push("/show/" + result.data.movie._id);
})
.catch(error => setShowLoading(false));
onSubmit();
};
return (
<div className="dzu-submitButtonContainer">
<button onClick={handleSubmit} className="dzu-submitButton">
Submit
</button>
</div>
);
};
const Preview = ({ meta, fileWithMeta }) => {
const { previewUrl, name, status, percent } = meta;
// const { uploadPercentage, setUploadPercentage } = useContext(AppContext);
// const timeout = useRef();
// console.log({ status });
// useEffect(() => {
// const time = 10000;
// if (uploadPercentage < 100) {
// timeout.current = setTimeout(() => {
// setUploadPercentage(uploadPercentage => uploadPercentage + 1);
// }, time / 1000);
// }
// return () => clearTimeout(timeout.current);
// }, []);
// console.log(uploadPercentage);
return (
<div className="dzu-previewContainer">
<img class="dzu-previewImage" src={previewUrl} alt={name} title={name} />
{status === 'done' ? <Clear onClick={fileWithMeta.remove} /> : ""}
</div>
);
};
const Layout = ({
input,
previews,
submitButton,
dropzoneProps,
files,
extra: { maxFiles }
}) => {
return (
<div>
<div>
{submitButton}
<HideMe>
<div {...dropzoneProps}>
{previews}
{files.length < maxFiles && input}
</div>
</HideMe>
</div>
</div>
);
};
const MyUploader = () => {
return (
<Dropzone
autoUpload={false}
SubmitButtonComponent={Submit}
PreviewComponent={Preview}
LayoutComponent={Layout}
onSubmit={() => {
console.log("After submit?");
}}
inputContent="Drop Files (Custom Layout)"
/>
);
};
const Edit = (props) => {
const { user, verified, setState } = useContext(MyTestStore);
const { movie, setMovie, showLoading } = useContext(AppContext);
return (
// <AppContext.Provider value={values}>
<MainContainer>
<MovieForm>
<MovieInfo>
{showLoading && <span className="sr-only">Loading...</span>}
<h2 className="title">Add Movie</h2>
<div className="wrapper">
<span>Title</span>
<input
className="no-outline"
type="text"
name="title"
defaultValue={movie.title}
onChange={e => setMovie({ ...movie, title: e.target.value })}
placeholder="Film Title"
/>
</div>
<div className="wrapper">
<span>Date</span>
<input
className="no-outline"
type="date"
name="date"
defaultValue={movie.date}
onChange={e => setMovie({ ...movie, date: e.target.value })}
/>
</div>
<div className="wrapper">
<span>Synopsis</span>
<textarea
className="no-outline"
type="text"
name="synopsis"
defaultValue={movie.synopsis}
onChange={e => setMovie({ ...movie, synopsis: e.target.value })}
placeholder="Synopsis"
/>
</div>
<div className="wrapper">
<span>Movie ID</span>
<input
className="no-outline"
type="text"
name="vID"
defaultValue={movie.id}
onChange={e => setMovie({ ...movie, vID: e.target.value })}
placeholder="Veezi Film ID"
/>
</div>
<div className="wrapper">
<span>Trailer</span>
<input
className="no-outline"
type="text"
name="trailer"
defaultValue={movie.trailer}
onChange={e => setMovie({ ...movie, trailer: e.target.value })}
placeholder="Trailer URL"
/>
</div>
</MovieInfo>
<MoviePosters>
<MyUploader />
</MoviePosters>
</MovieForm>
</MainContainer>
// </AppContext.Provider>
);
};
export default withRouter(Edit);
应用路由
import { Route, Switch, Router } from "react-router-dom";
import { createBrowserHistory } from "history";
import { checkLoggedIn } from "../util/session";
import "./xApp.css";
// import "../script";
import { AuthRoute, ProtectedRoute } from "./Login";
import AddFilm from "./AddFilm";
import Movies from "./xMovies";
import Welcome from "./Welcome";
import Login from "./Login";
import Signup from "./Signup";
import Admin from "./xAdmin";
import Dashboard from "./xDashboard";
import AdminPage from "./xPage";
import EditPage from "./EditPage";
import Create from "./Create";
// import CreateForm from "./CreateForm";
import Edit from "./EditForm";
import Show from "./Show";
import List from "./List";
import Reviews from "./Reviews";
import BoxOffice from "./BoxOffice";
import Trash from "./Trash";
const history = createBrowserHistory();
export const MyTestStore = React.createContext({})
export default ((props) => {
const [state, setState] = useState({})
useEffect(() => {
async function appCheckLoggedIn() {
const result = await checkLoggedIn();
if (result) {
console.log({user, verified: true})
console.log(result.session);
const user = result.session
setState({user, verified: true})
} else {
console.log({verified: true})
setState({verified: true})
}
}
// Execute the created function directly
appCheckLoggedIn();
}, [])
const loggedIn = !!state.user
return (
<>
<MyTestStore.Provider value={{...state, setState}}>
<Router history={history}>
<Switch>
<Route exact path="/" component={Welcome} />
<Route path="/list" component={List} />
<AuthRoute path="/login" component={Login} />
<AuthRoute path="/signup" component={Signup} />
<ProtectedRoute exact path="/admin" component={Dashboard} layout={AdminPage} />
<ProtectedRoute exact path="/admin/movies" component={Movies} layout={AdminPage} />
<ProtectedRoute exact path="/admin/movies/new" component={Create} layout={EditPage} />
<ProtectedRoute path="/admin/movies/edit/:_id" component={Edit} layout={EditPage} />
<ProtectedRoute exact path='/admin/movies/show/:_id' component={Show} layout={AdminPage} />
<ProtectedRoute exact path="/admin/reviews" component={Reviews} layout={AdminPage} />
<ProtectedRoute exact path="/admin/box-office" component={BoxOffice} layout={AdminPage} />
<ProtectedRoute exact path="/admin/trash" component={Trash} layout={AdminPage} />
{loggedIn && <Admin /> || null }
</Switch>
</Router>
</MyTestStore.Provider>
</>
)})
快速路线
const express = require('express');
const router = express.Router();
const bodyParser = require('body-parser')
const upload = require('../config/multer.config.js');
const app = express();
fs = require('fs-extra')
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}))
// Load Movie model
const Movie = require('../models/movie');
// @route GET api/movies/test
// @trailer tests movies route
// @access Public
router.get('/test', (req, res) => res.send('movie route testing!'));
// @route GET api/movies
// @trailer Get all movies
// @access Public
router.get('/', (req, res) => {
Movie.find()
.then(movies => res.json(movies))
.catch(err => res.status(404).json({ nomoviesfound: 'No Movies found' }));
});
// @route GET api/movies/:id
// @trailer Get single movie by id
// @access Public
router.get('/:id', (req, res) => {
Movie.findById(req.params.id)
.then(movie => res.json(movie))
.catch(err => res.status(404).json({ nomoviefound: 'No Movie found' }));
});
// @route GET api/movies
// @trailer add/save movie
// @access Public
router.post('/', upload.array('poster'), (req, res) => {
var filenames = req.files.map(function(file) {
return file.path; // or file.originalname
});
var a = (filenames.findIndex(function(item){
return item.indexOf("poster")!==-1;
}));
var b = (filenames.findIndex(function(item){
return item.indexOf("slide")!==-1;
}));
console.log(filenames);
// console.log(movieData);
// console.log(req.body);
// console.log(req.files);
var date = new Date(req.body.date);
// var isoString = date.toISOString();
var movieData = {
id: req.body.id,
title: req.body.title,
synopsis: req.body.synopsis,
trailer: req.body.trailer,
OpeningDate: date,
poster: filenames[a],
slide: filenames[b]
};
let movie = new Movie(movieData);
movie.save()
.then(() => res.json({ movie, msg: 'New movie added successfully' }))
.catch(err => res.status(400).json('Unable to add this movie'))
});
// @route GET api/movies/:id
// @trailer Update movie
// @access Public
router.post('/:id', upload.array('posters'), (req, res) => {
Movie.findByIdAndUpdate(req.params.id)
.then(movie => {
movie.id = req.body.id,
movie.title = req.body.title,
movie.synopsis = req.body.synopsis,
movie.trailer = req.body.trailer
console.log(req.files);
console.log(req.files.length);
if (req.files.length > 0) {
console.log('hi');
var filenames = req.files.map(function(file) {
return file.path; // or file.originalname
});
var a = (filenames.findIndex(function(item){
return item.indexOf("poster")!==-1;
}));
var b = (filenames.findIndex(function(item){
return item.indexOf("slide")!==-1;
}));
console.log(a);
if (a >= 0) {
movie.poster = filenames[a]
}
if (b >= 0) {
movie.slide = filenames[b]
}
}
console.log(movie);
movie.save()
.then(() => res.json({ movie, msg: 'Updated successfully' }))
.catch(err =>
res.status(400).json('Unable to update the Database'))
})
.catch(err =>
res.status(400).json('Unable to update the Database'));
});
// @route GET api/movies/:id
// @trailer Delete movie by id
// @access Public
router.delete('/:id', (req, res) => {
Movie.findByIdAndRemove(req.params.id)
.then(() => res.json('Movie entry deleted successfully'))
.catch(err => res.status(404).json({ error: 'No such a movie' }));
});
module.exports = router;
答案 0 :(得分:0)
假设“编辑”组件的道具中获得正确的值,则可以在“编辑”中移动“提交”以共享相同的道具。像这样:
const Edit = (props) => {
...
const Submit = () => {
// here you'll have access to the props passed into Edit
...
};
const Preview = ({...}) => {
...
};
const Layout = ({...}) => {
...
};
const MyUploader = () => {
...
};
return (
<MainContainer>
...
</MainContainer>
);
};