react上下文
It’s common in React for data to flow from top to bottom through props (parent component to children components), but this is not ideal all the time.
在React中,数据通过道具(父组件到子组件)从上到下流动是很常见的,但这并不总是很理想。
Here’s a simple example:
这是一个简单的例子:
<Page user={user} avatarSize={avatarSize} />
// ... which renders ...
<PageLayout user={user} avatarSize={avatarSize} />
// ... which renders ...
<NavigationBar user={user} avatarSize={avatarSize} />
// ... which renders ...
<Link href={user.permalink}>
<Avatar user={user} size={avatarSize} />
</Link>
In the above code, only the Avatar
component actually uses the user
prop, however each of its ancestor (parent, grandparent, etc) components receive user
and pass it down. This means that if the Avatar
component needed another prop in the future, we’d have to ensure that each of its ancestor components receive and pass it down. This makes our code difficult to maintain and error-prone.
在上面的代码中,只有Avatar
组件实际上使用了user
道具,但是其每个祖先(父母,祖父母等)组件都接收user
并将其传递给user
。 这意味着如果Avatar
组件将来需要另一个道具,我们必须确保其每个祖先组件都可以接收并传递给它。 这使我们的代码难以维护且容易出错。
In reality, the user
state will need to be shared across many different components, therefore passing it as a prop will result it in nesting even deeper than the above example. In this situation, it may seem like a good idea to use Redux to manage state, but many argue it should not be your first option. So if not Redux, then what?
实际上, user
状态将需要在许多不同的组件之间共享,因此将其作为道具传递将导致其嵌套比上述示例还要深。 在这种情况下,使用Redux来管理状态似乎是一个好主意,但是许多人认为这不应该是您的首选 。 那么,如果不是Redux,那又如何呢?
React Context is an alternative solution to sharing data across components, without having to pass props down manually at every level. This post will explore the Context API and show how it can be used to manage user state.
React Context是一种跨组件共享数据的替代解决方案,而无需在每个级别手动传递道具。 这篇文章将探索Context API,并展示如何将其用于管理用户状态。
React.createContext (React.createContext)
The React.createContext
method returns a Context
object. This Context
object comes with two important React components that allow for subscribing to data: Provider
and Consumer
.
React.createContext
方法返回一个Context
对象。 这个Context
对象带有两个重要的React组件,它们允许订阅数据: Provider
和Consumer
。
When React renders a component that subscribes to this Context
object it will read the current context value from the closest matching Provider
component above it in the tree. Let’s see what that means:
当React渲染一个订阅该Context
对象的组件时,它将从树中它上面最接近的匹配Provider
组件读取当前上下文值。 让我们看看这意味着什么:
const userContext = React.createContext({user: {}}); // Create a context object
export {
userContext // Export it so it can be used by other Components
};
The createContext
method takes in an optional defaultValue
argument, which is provided to Context.Consumer
if a matching Context.Provider
component could not be found in the tree. In the example above we initialize userContext
and provide defaultValue of {user: {}}
.
如果在树中找不到匹配的Context.Provider
组件,则createContext
方法采用可选的defaultValue
参数,该参数将提供给Context.Consumer
。 在上面的示例中,我们初始化了userContext
并提供了{user: {}}
defaultValue。
Now that we have a Context
object we can provide it with a value and subscribe to changes.
现在我们有了一个Context
对象,我们可以为其提供一个值并订阅更改。
上下文提供者 (Context.Provider)
import {userContext} from './userContext';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
user: {}
};
}
componentDidMount() {
// get and set currently logged in user to state
}
render() {
return (
// Pass user state as value to context.Provider so it can be consumed by context.Consumer
<userContext.Provider value={this.state.user}>
<Main/>
</userContext.Provider>
);
}
}
This is great to start with, wrapping the Main
component with userContext.Provider
ensures that the value we pass can be consumed within any of Main
’s descendant child components. But how exactly do you consume?
首先,用userContext.Provider
包装Main
组件是很不错的userContext.Provider
确保我们传递的值可以在Main
的所有子组件中使用。 但是你到底怎么消费 ?
上下文消费者 (Context.Consumer)
import {userContext} from './userContext';
function Main(props) {
return (
<Sidebar/>
<userContext.Consumer>
{(value) => (<Avatar user={value}/>);}
</userContext.Consumer>
<Content/>
)
}
userContext.Consumer
takes in a function as a child. This function receives the current context value (value that is passed as a prop to userContext.Provider
) and returns a React node. In this case it receives the App
component’s state.user
as value and renders an Avatar
component.
userContext.Consumer
将函数作为子级。 此函数接收当前上下文值(作为prop传递给userContext.Provider
),并返回一个React节点。 在这种情况下,它接收App
组件的state.user
作为值,并呈现Avatar
组件。
从嵌套组件更新上下文 (Updating Context from Nested Components)
Up to this point, we’ve used React Context to pass data to components that need it without having to manually pass props. Next, we need to be able to update the context from a nested child component. A logout button, for example.
到目前为止,我们已经使用React Context将数据传递到需要它的组件,而无需手动传递prop。 接下来,我们需要能够从嵌套的子组件中更新上下文。 例如,注销按钮。
In this case, you can pass a function down through the same context to allow consumers to update the context.
在这种情况下,您可以将功能向下传递到同一上下文,以允许使用者更新上下文。
import {userContext} from './userContext';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
user: {}
};
this.logout = this.logout.bind(this);
}
// Add a logout method
logout() {
this.setState({user: {}});
}
componentDidMount() {
// get and set currently logged in user to state
}
render() {
// compose value prop as object with user object and logout method
const value = {
user: this.state.user,
logoutUser: this.logout
}
return (
<userContext.Provider value={value}>
<Main/>
</userContext.Provider>
);
}
}
The function that is passed to update context can be used in any nested component within the userContext.Provider
component.
传递给更新上下文的函数可以在userContext.Provider
组件内的任何嵌套组件中使用。
import {userContext} from './userContext';
function Main(props) {
return (
<Sidebar/>
<userContext.Consumer>
{({user, logoutUser}) => {
return (
<Avatar user={user}/>
<LogoutButton onClick={logoutUser}/>
);
}}
</userContext.Consumer>
<Content/>
)
}
And that concludes a simple example of how to use React’s Context API to manage user state.
并得出一个简单的示例,说明如何使用React的Context API管理用户状态。
翻译自: https://www.digitalocean.com/community/tutorials/react-manage-user-login-react-context
react上下文