所以,我有两个组件,一个组件始终是另一个组件的直系后代。我想将道具从父组件传递给子组件。可能有多个子组件。有两种方法可以实现它。
React.Children.map(children, (child) =>
React.cloneElement(child, { someProp: 'value' })
)
Run Code Online (Sandbox Code Playgroud)
或使用上下文 API
<Context.Provider value={{ someProp: 'value' }}>
{this.props.children}
</Context.Provider>
Run Code Online (Sandbox Code Playgroud)
两者都会产生相同的 DOM 结构,但是 Context API 的代码稍微多一些,并且会产生更多的 React 组件。
那么哪一款更注重性能,值得推荐。我找不到与此比较相关的任何讨论,因此在这里询问。
我试图迁移react-redux v5.X.X到v6.0.0该站点,似乎没有任何文档。我正在使用以下版本:
"react": "^16.4.2"
"redux": "^4.0.0"
"react-redux": "^6.0.0"
官方更改日志说。
不再支持将存储作为道具传递给已连接的组件。相反,您可以向和都传递自定义context = {MyContext}属性。您也可以通过{context:MyContext}作为连接选项。链接在这里
这是我的根 index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import { configureStore, history } from './Store';
import App from './App.hot';
import 'antd/dist/antd.min.css';
const reduxStore = configureStore();
ReactDOM.render(<App store={reduxStore} history={history} />, document.getElementById('root'));
Run Code Online (Sandbox Code Playgroud)
这是我的app.jsx(根组件)
import React from 'react';
import PropTypes from 'prop-types';
import { Provider, connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { ConnectedRouter } from 'connected-react-router';
import …Run Code Online (Sandbox Code Playgroud) 不过,我面临的问题是,我想在整个组件树状结构中模仿 React 中 FlaskLogin current_user 的行为。对于不熟悉 FlaskLogin 的任何人,current_user只需存储当前登录用户的会话。
为此,我决定使用 React 上下文 api。我所做的是在顶级组件中,我将一个 UserProvider 包裹在应用程序周围,如下所示:
<UserProvider value={this.state.user}>
// Main Component.
</UserProvider>
Run Code Online (Sandbox Code Playgroud)
状态在构造函数中定义:
constructor() {
super();
this.state = {
user: {
id: -1,
username: ‘test username’,
email: 'test email’,
},
};
}
Run Code Online (Sandbox Code Playgroud)
然后我在 componentDidMount 中调用一个 Ajax 请求来获取 current_user。
componentDidMount() {
const state = this;
post('/get_current_user').then(function success(data) {
state.setState({
user: {
id: data.data.id,
username: data.data.username,
email: data.data.email,
},
});
}).catch(function exception() {
throw new Error('Failed to grab current user.');
});
} …Run Code Online (Sandbox Code Playgroud) 如果用户经过身份验证并可以通过React Context API访问它,我想保存一个简单的布尔值 + userID 。
许多指南用上下文提供者包装了他们的根组件。对我来说,包装整个应用程序似乎很浪费。另一方面,我需要在我的所有主页中提供此信息。
用 React Context Provider 包装整个应用程序会产生负面影响吗?
例子:
class App extends Component {
render() {
return (
<MyProvider>
<div className="App">
<h1 className="App-title">Welcome to my web store</h1>
<ProductList />
</div>
</MyProvider>
);
}
Run Code Online (Sandbox Code Playgroud)
}
我使用本指南作为参考。
我没有任何 React Redux 经验,所以这对于以前使用过这个框架的每个人来说可能都很自然。
研究 Google 后发现了许多关于如何实现 React Context 或使用 HOC 的指南,但我点击的 15 个指南并没有回答我的问题。
我将Gatsby用作静态网站生成器。我使用React Context API来存储用户已通过身份验证的信息。
在开发模式下,当我键入任何重定向到404错误页面的URL时,上下文数据将丢失。当我导航到有效页面时,以前登录的用户不再登录。
我之前从未使用过React Context,所以不确定如何处理。那是预期的行为吗?有什么方法可以保留用户特定的React Context?我是否需要从后端重新提供上下文?还是我只是犯了一个错误?最好的行动方针是什么?
我想以某种方式将上下文保留在浏览器中,直到会话超时。尚未执行来自后端的会话处理。
编辑:我刚刚用gatsby构建和gatsby服务测试了这一点。当重定向到404错误页面时,内置的gatsby网站会保留上下文。但是,当导航到完全不同的URL(例如www.google.com)时,上下文仍然丢失。
现在我的问题是:如何在不让用户再次手动登录的情况下为上下文提供登录信息?Cookie检查?抱歉,如果我要问一个明显的问题。我从未实现过会话或cookie。
这是我的AuthContextProvider包装器类:
import React from "react";
export const AuthContext = React.createContext();
export class AuthContextProvider extends React.Component {
state = {
authenticated: false,
toggleLogin: () => {},
userid: null,
};
render() {
return (
<AuthContext.Provider
value={{
authenticated: this.state.authenticated,
userid: this.state.userid,
toggleLogin: () => {
const previousValueState = this.state.authenticated;
this.setState(state => ({
authenticated: !previousValueState,
userid: 2,
}));
},
}}
>
{this.props.children}
</AuthContext.Provider>
);
}
}
Run Code Online (Sandbox Code Playgroud)
我用Context Provider将整个应用程序包装在根布局中:
export default function RootLayout({ …Run Code Online (Sandbox Code Playgroud) 因此,门户解决的一个有趣且令人惊奇的属性是保留来自提供者的上下文,即使您的组件需要在其他地方呈现也是如此。如果您使用 ContextProvider 包装组件子树,则在该子树中呈现的任何组件都将有权访问上下文值。
反过来,如果您在子树之外渲染某些内容,它就无法访问该上下文。React Portals 解决了这个问题,所以如果你想渲染子树之外的东西,你可以在同一个子树内完成它。我认为React 文档对此有所涉及:
无论子级是否是门户,诸如上下文之类的功能都完全相同,因为无论 DOM 树中的位置如何,门户仍然存在于 React 树中。
我想我并没有概念化它实际上是如何工作的。React Portal 如何能够访问 Context 而无需在同一子树中渲染?听起来在幕后,Portal 是“React Tree”的一部分?那么一定有一些奇特的“传递信息然后渲染门户逻辑”?明确我的问题
门户究竟如何工作来保留对上下文值的访问?
我正在尝试访问我的 Apollo 客户端的 setContext 函数中的反应上下文值。我希望能够使用反应上下文值动态更新每个 graphql 请求的标头。但是我遇到了一个错误,日志中没有可见的错误消息。我正在尝试做的可能吗?
import React, { useState, useContext } from "react";
import { render } from "react-dom";
import ApolloClient from "apollo-client";
import { ApolloProvider } from "react-apollo";
import { createHttpLink } from "apollo-link-http";
import { setContext } from "apollo-link-context";
import { InMemoryCache } from "apollo-cache-inmemory";
import Select from "./Select";
import CurrencyContext from "./CurrencyContext";
import ExchangeRates from "./ExchangeRates";
const httpLink = createHttpLink({
uri: "https://48p1r2roz4.sse.codesandbox.io"
});
const authLink = setContext((_, { headers }) => {
const token = …Run Code Online (Sandbox Code Playgroud) reactjs react-apollo apollo-client react-context react-hooks
我有一个应用程序,用户将单击应用程序的各个部分,这将在右侧的抽屉中显示某种配置选项。
我对此的解决方案是将要显示的任何内容存储在上下文中。这样,抽屉只需要从上下文中检索其内容,并且需要设置内容的任何部分都可以直接通过上下文进行设置。
这是一个CodeSandbox 演示了这一点。
关键代码片段:
const MainContent = () => {
const items = ["foo", "bar", "biz"];
const { setContent } = useContext(DrawerContentContext);
/**
* Note that in the real world, these components could exist at any level of nesting
*/
return (
<Fragment>
{items.map((v, i) => (
<Button
key={i}
onClick={() => {
setContent(<div>{v}</div>);
}}
>
{v}
</Button>
))}
</Fragment>
);
};
const MyDrawer = () => {
const classes = useStyles();
const { content } = useContext(DrawerContentContext); …Run Code Online (Sandbox Code Playgroud) 问题已在github上跟踪
我试图使用反应测试库来测试自定义挂钩,并且我试图测试的挂钩需要多个上下文提供程序才能正常工作。(认证和通知)
这里的文档仅概述了使用单个提供程序创建包装器,如下所示:
const wrapper = ({ children }) => <ContextProvider>{children}</ContextProvider>
Run Code Online (Sandbox Code Playgroud)
但是,我的实现需要更复杂的东西,如下所示:
const wrapper = ({ children }) => (
<ToastProvider>
<NotificationProvider>
<AuthProvider>{children}</AuthProvider>
</NotificationProvider>
</ToastProvider>
);
Run Code Online (Sandbox Code Playgroud)
每次尝试都失败并出现以下错误:
TypeError: parentInstance.children.indexOf is not a function
Run Code Online (Sandbox Code Playgroud)
或者
Invariant Violation: Drop(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.
Run Code Online (Sandbox Code Playgroud)
让我相信,如果不放弃 renderHook 并构建一个可以手动触发必要行为的测试组件,就没有明确的方法来提供正确的上下文。
经过更多挖掘后,我发现这个错误隐藏在日志中:
Warning: An invalid container has been provided. This may indicate that another renderer is being …Run Code Online (Sandbox Code Playgroud) reactjs jestjs react-context react-testing-library react-hooks
我在 React 中使用上下文提供程序来跨多个组件共享数据。然而,由于我的一个子组件的值发生了变化,它会重新渲染我的所有其他组件,这在一定程度上导致了性能问题。所以我想阻止我的子组件重新渲染。我尝试使用 React.memo() 但每当我设置 Context Provider 的状态时它仍然会呈现。
const Authenticator = React.memo(() => {
const [myChat, setMyChat] = useContext(ChatContext);
console.log("rerender"); // gets called everytime on click
return (
<Button
title="click me"
onPress={() => setMyChat({ text: "hello" })}
></Button>
);
});
Run Code Online (Sandbox Code Playgroud)
我的上下文提供程序如下所示:
const ChatProvider = ({ children }) => {
const [myChat, setMyChat] = useState([]);
return (
<ChatContext.Provider value={[myChat, setMyChat]}>
{children}
</ChatContext.Provider>
);
};
Run Code Online (Sandbox Code Playgroud)
我的 App.js 如下所示:
<ChatProvider>
<Authenticator />
</ChatProvider>
Run Code Online (Sandbox Code Playgroud) react-context ×10
reactjs ×10
javascript ×4
react-hooks ×2
formik ×1
gatsby ×1
jestjs ×1
memoization ×1
performance ×1
react-apollo ×1
react-native ×1
react-portal ×1
react-redux ×1