为什么在 nextjs 中状态没有被解析为变量
Why a state is not resolved as a variable in nextjs
我正在使用 passportjs 中间件进行身份验证并且它有效,但是当我尝试在组件中使用用户对象时,属性 未定义,尽管在 _app.js 中传递。
该应用程序是基于 nextjs 的快速服务器。我知道用户已通过身份验证,因为我可以在服务器中跟踪它,但不能在任何组件中跟踪它。
// _app.js
import React from 'react';
import App, { Container } from 'next/app';
import { ThemeProvider } from '@material-ui/styles';
import theme from '../theme/theme';
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
if (ctx.req && ctx.req.session && ctx.req.session.passport) {
pageProps.user = ctx.req.session.passport.user;
}
return { pageProps };
}
constructor(props) {
super(props);
this.state = {
user: props.pageProps.user
};
}
render() {
const { Component, pageProps } = this.props;
const props = {
...pageProps,
user: this.state.user,
};
return (
<Container>
<ThemeProvider theme={theme}>
<Component {...props} />
</ThemeProvider>
</Container>
);
}
}
export default MyApp;
Webstorm 指向 user: this.state.user
行,抱怨未解析的变量 user
但我不明白为什么没有解析为变量,它是在构造函数中定义的。
编辑:这是 server.js
const express = require("express");
const http = require("http");
const next = require("next");
const session = require("express-session");
const passport = require("passport");
const uid = require('uid-safe');
const authRoutes = require("./auth-routes");
const oAuth2Strategy = require("./lib/passport-oauth2-userinfo");
const dev = process.env.NODE_ENV !== "production";
const app = next({
dev,
});
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
const sessionConfig = {
secret: uid.sync(18),
cookie: {
maxAge: 86400 * 1000 // 24 hours in milliseconds
},
resave: false,
saveUninitialized: true
};
server.use(session(sessionConfig));
passport.use(new oAuth2Strategy(
{
authorizationURL: process.env.REACT_APP_AUTH_URL,
tokenURL: process.env.REACT_APP_AUTH_TOKEN,
clientID: process.env.REACT_APP_CLIENT_ID,
clientSecret: process.env.REACT_APP_SECRET,
callbackURL: process.env.REACT_APP_CALLBACK,
userProfileURL: process.env.REACT_APP_OPENID
},
function(accessToken, refreshToken, extraParams, profile, done) {
console.log(profile);
return done(null, profile);
}
));
passport.serializeUser((user, done) => done(null, user));
passport.deserializeUser((user, done) => done(null, user));
server.use(passport.initialize());
server.use(passport.session());
server.use(authRoutes);
const restrictAccess = (req, res, next) => {
if (!req.isAuthenticated()) return res.redirect("/login");
next();
};
server.use("/", restrictAccess);
server.use("/profile", restrictAccess);
server.get("*", handle);
http.createServer(server).listen(process.env.PORT, () => {
console.log(`listening on port ${process.env.PORT}`);
});
});
编辑 2:感谢@SimplyComplexable,我解决了一些问题。在我的 index.js 中,我可以像这样访问用户道具,例如this.props.user.displayName
没问题。
这个有效:
import Landing from "./Landing"
import React from "react";
class Home extends React.Component {
render() {
return (
<div>
{this.props.user.displayName}
<Landing />
</div>
)
}
}
export default Home;
但是,例如,在 Landing
组件中,prop.user 是未定义的。也许我没有正确访问或以某种方式传递道具?
class Landing extends React.Component {
const {user} = this.props;
return (
<div>
...
)
}
export default withStyles(useStyles)(Landing);
基于您现在拥有的代码的问题是您没有将 user
传递给 Landing
组件。
如果您使用以下更改更新您的主页,您的代码应该可以工作。
import Landing from "./Landing"
import React from "react";
class Home extends React.Component {
render() {
return (
<div>
{this.props.user.displayName}
<Landing user={this.props.user}/>
</div>
)
}
}
export default Home;
对于特定用户来说,这对 context 来说是一个很好的机会,这样您就不必明确地将用户属性传递给每个组件。
这是一个简单的例子:
import Landing from "./Landing"
import React from "react";
export const UserContext = React.createContext({});
class Home extends React.Component {
render() {
return (
<div>
{this.props.user.displayName}
<UserContext.Provider value={this.props.user}>
<Landing user={this.props.user}/>
</UserContext.Provider>
</div>
)
}
}
export default Home;
import React from 'react';
import UserContext from './Home';
const Landing = () => {
const user = React.useContext(UserContext);
return (
<div>
{user.displayName}
</div>
)
}
export default withStyles(useStyles)(Landing);
我正在使用 passportjs 中间件进行身份验证并且它有效,但是当我尝试在组件中使用用户对象时,属性 未定义,尽管在 _app.js 中传递。
该应用程序是基于 nextjs 的快速服务器。我知道用户已通过身份验证,因为我可以在服务器中跟踪它,但不能在任何组件中跟踪它。
// _app.js
import React from 'react';
import App, { Container } from 'next/app';
import { ThemeProvider } from '@material-ui/styles';
import theme from '../theme/theme';
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
if (ctx.req && ctx.req.session && ctx.req.session.passport) {
pageProps.user = ctx.req.session.passport.user;
}
return { pageProps };
}
constructor(props) {
super(props);
this.state = {
user: props.pageProps.user
};
}
render() {
const { Component, pageProps } = this.props;
const props = {
...pageProps,
user: this.state.user,
};
return (
<Container>
<ThemeProvider theme={theme}>
<Component {...props} />
</ThemeProvider>
</Container>
);
}
}
export default MyApp;
Webstorm 指向 user: this.state.user
行,抱怨未解析的变量 user
但我不明白为什么没有解析为变量,它是在构造函数中定义的。
编辑:这是 server.js
const express = require("express");
const http = require("http");
const next = require("next");
const session = require("express-session");
const passport = require("passport");
const uid = require('uid-safe');
const authRoutes = require("./auth-routes");
const oAuth2Strategy = require("./lib/passport-oauth2-userinfo");
const dev = process.env.NODE_ENV !== "production";
const app = next({
dev,
});
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
const sessionConfig = {
secret: uid.sync(18),
cookie: {
maxAge: 86400 * 1000 // 24 hours in milliseconds
},
resave: false,
saveUninitialized: true
};
server.use(session(sessionConfig));
passport.use(new oAuth2Strategy(
{
authorizationURL: process.env.REACT_APP_AUTH_URL,
tokenURL: process.env.REACT_APP_AUTH_TOKEN,
clientID: process.env.REACT_APP_CLIENT_ID,
clientSecret: process.env.REACT_APP_SECRET,
callbackURL: process.env.REACT_APP_CALLBACK,
userProfileURL: process.env.REACT_APP_OPENID
},
function(accessToken, refreshToken, extraParams, profile, done) {
console.log(profile);
return done(null, profile);
}
));
passport.serializeUser((user, done) => done(null, user));
passport.deserializeUser((user, done) => done(null, user));
server.use(passport.initialize());
server.use(passport.session());
server.use(authRoutes);
const restrictAccess = (req, res, next) => {
if (!req.isAuthenticated()) return res.redirect("/login");
next();
};
server.use("/", restrictAccess);
server.use("/profile", restrictAccess);
server.get("*", handle);
http.createServer(server).listen(process.env.PORT, () => {
console.log(`listening on port ${process.env.PORT}`);
});
});
编辑 2:感谢@SimplyComplexable,我解决了一些问题。在我的 index.js 中,我可以像这样访问用户道具,例如this.props.user.displayName
没问题。
这个有效:
import Landing from "./Landing"
import React from "react";
class Home extends React.Component {
render() {
return (
<div>
{this.props.user.displayName}
<Landing />
</div>
)
}
}
export default Home;
但是,例如,在 Landing
组件中,prop.user 是未定义的。也许我没有正确访问或以某种方式传递道具?
class Landing extends React.Component {
const {user} = this.props;
return (
<div>
...
)
}
export default withStyles(useStyles)(Landing);
基于您现在拥有的代码的问题是您没有将 user
传递给 Landing
组件。
如果您使用以下更改更新您的主页,您的代码应该可以工作。
import Landing from "./Landing"
import React from "react";
class Home extends React.Component {
render() {
return (
<div>
{this.props.user.displayName}
<Landing user={this.props.user}/>
</div>
)
}
}
export default Home;
对于特定用户来说,这对 context 来说是一个很好的机会,这样您就不必明确地将用户属性传递给每个组件。 这是一个简单的例子:
import Landing from "./Landing"
import React from "react";
export const UserContext = React.createContext({});
class Home extends React.Component {
render() {
return (
<div>
{this.props.user.displayName}
<UserContext.Provider value={this.props.user}>
<Landing user={this.props.user}/>
</UserContext.Provider>
</div>
)
}
}
export default Home;
import React from 'react';
import UserContext from './Home';
const Landing = () => {
const user = React.useContext(UserContext);
return (
<div>
{user.displayName}
</div>
)
}
export default withStyles(useStyles)(Landing);