react context_使用React Context API-入门

react context

Let's use the React Context API to change theme in an app!

让我们使用React Context API更改应用程序中的主题!

但是首先,一些背景 ! ? (But first, some context! ?)

Ok terrible puns aside let's have a look at what the React Context API is for and what it does. There's a great one liner from the React docs...

除了糟糕的双关语,我们来看一下React Context API的用途和作用。 React文档中有一个很好的衬里...

Context provides a way to pass data through the component tree without having to pass props down manually at every level.

上下文提供了一种通过组件树传递数据的方法,而不必在每个级别手动传递道具。

Or in other words, you can use the React Context API to avoid prop drilling if you need more detail on the concept then please do check out the links provided.

换句话说,如果您需要有关概念的更多详细信息,则可以使用React Context API来避免进行钻探 ,然后请检查提供的链接。

I've previously gone over implementing the React Context API in my Gatsby blog which I documented as I did it; you can see how that went here.

之前,我已经在我的Gatsby博客中介绍了实现React Context API的方法,并在此过程中进行了记录。 你可以看到这里的情况

向我解释上下文API。 (Explain the Context API to me.)

A great resource on explaining the API can be found from @leighchalliday with a great usecase on the subject.

可以在@leighchalliday上找到有关解释API的大量资源,并提供有关该主题的大量用例

我们在做什么... (What we're doing...)

For this post we're going to extend the example we created for styled-components getting started as it has the majority of the code we'll need to get started with the React Context API.

在这篇文章中,我们将扩展为样式组件入门而创建的示例,因为它具有使用React Context API入门所需的大部分代码。

We're going to extend that example to manage the theme state of the example application.

我们将扩展该示例以管理示例应用程序的主题状态。

So in summary:

因此,总而言之:

  • Scaffold out basic CreateReact App

    搭建基本的CreateReact App
  • Use styled-components ? for styling

    使用样式组件? 用于造型
  • Add themes to switch between with the React Context API

    添加主题以在React Context API之间切换
  • Use the React Context API!

    使用React Context API!

我们需要... (What we'll need...)

All we'll be needing is an internet connection and a modern web browser! Because we're going to do all of this online in the awesome CodeSandbox!

我们所需要的只是互联网连接和现代的网络浏览器! 因为我们要在真棒的CodeSandbox中在线完成所有这些工作

If you have a GitHub account or not, CodeSandbox will let you get started coding straight away!

如果您没有GitHub帐户,CodeSandbox将让您立即开始编码

版本: (Versions:)

This guide is being used with the following dependency versions.

本指南与以下依赖项版本一起使用。

  • react: 16.4.2

    React:16.4.2
  • react-dom: 16.4.2

    React区:16.4.2
  • react-scripts: 1.1.4

    React脚本:1.1.4
  • styled-components: 3.4.5

    样式组件:3.4.5


开始吧 (Let's start)

So let's go over theming the basic create react app again, this time instead of adding state into to the component we will use the React Context API to manage the state for us. There will be people that will argue that this is a bit overkill for a theme switch but it is given as an example of when to use the Context API in the React documentation so I will let you decide on the validity of that point. For this example, I hope it will give you a clearer picture of how to use the Context API in an application.

因此,让我们再次对基本的create react应用程序进行主题设置,这次而不是将状态添加到组件中,我们将使用React Context API为我们管理状态。 会有人争辩说,这对于主题切换来说有点矫kill过正,但是它作为在React文档中何时使用Context API的示例,因此我将让您决定这一点的有效性。 对于此示例,希望它可以使您更清楚地了解如何在应用程序中使用Context API。

依存关系 (Dependencies)

Open a React CodeSandbox and add styled-components as a dependency:

打开一个React CodeSandbox并添加styled-components作为依赖项:

档案结构 (File structure)

Another area for bikeshedding is file structure, in this scenario we're adding folders for components, contexts and the theme please feel free to structure your files how you see fit, this is how we're going to do it for this example ❤️

自行车脱落的另一个领域是文件结构,在这种情况下,我们将为componentscontextstheme添加文件夹,请随意按照自己认为合适的方式来构建文件,这就是我们在此示例中要做的方式❤️

Add the directories into the src folder so we can add in some components, the file structure should look something like this:

将目录添加到src文件夹中,以便我们可以添加一些组件,文件结构应如下所示:

context-demo/
├─ public/
├─ src/
│  └─ components/
│  └─ contexts/
│  └─ theme/
└─ package.json

搭建基本的Create React App (Scaffold out a basic Create React App)

Ok, so, what we're going to do is add in an App.js component to the components folder then use that in the src/index.js file.

好的,所以我们要做的是将App.js组件添加到components文件夹中,然后在src/index.js文件中使用它。

The App.js component can be a stateless functional component as for this example as we're going to be handling state with the Context API.

就本例而言, App.js组件可以是无状态功能组件 ,因为我们将使用Context API处理状态。

Here you can see my sketchy typing as I create the directories and add in the App.js component.

在这里,您可以看到创建目录并添加App.js组件时的粗略输入。

We can then remove the style.css file and reference in src/index.js as we're going to be styling with styled-components ? and then use our App.js component:

然后,我们可以删除style.css文件并在src/index.js引用,因为我们将使用样式化组件进行样式设置? 然后使用我们的App.js组件:

Ok, so the reason why I have abstracted the App.js component out of the src/index.js file is so that when we come to using the Context API we can add it to the highest level in our app, which is src/index.js.

好的,所以我之所以从src/index.js文件中抽象出App.js组件是因为当我们使用Context API时,可以将其添加到应用程序的最高级别,即src/index.js

其余的呢? (What about the rest?)

So this isn't really the Create React App, as we're using CodeSandbox instead, I have gone over the basic styling used in the styled-components getting started post so it's time to refer to that to mimic the styles we need.

因此,这并不是真正的Create React App,因为我们使用的是CodeSandbox,所以我已经遍历了样式化组件入门中使用的基本样式,现在是时候引用它来模仿我们需要的样式了。

That means what we're going to do, rather than go into depth on the styling of each of the component parts that make up the basic Create React App appearance, we're going to re-use components, so there's going to be a bit of copy pasting involved now.

这意味着我们将要做的是,而不是深入构成基本的React React App外观的每个组件的样式,我们将重用组件,因此将有一个现在涉及一些复制粘贴。

The Create React App boilerplate code has one file that we go over styling in the styled-components getting started post which is the App.js file, the others are left or deleted, the basic style of App.js is:

Create React App样板代码中有一个文件,我们将在样式化组件入门文章中介绍样式 ,即App.js文件, App.js文件则保留或删除, App.js的基本样式为:

App.css

App.css

.App {
  text-align: center;
}

.App-logo {
  animation: App-logo-spin infinite 20s linear;
  height: 80px;
}

.App-header {
  background-color: #222;
  height: 150px;
  padding: 20px;
  color: white;
}

.App-title {
  font-size: 1.5em;
}

.App-intro {
  font-size: large;
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

使用样式化的组件进行样式化 (Use styled components for styling)

Now we're going to recreate the styles from the App.css file with styled-components, let's list them out here and go through them:

现在,我们将使用样式组件从App.css文件中重新创建样式,让我们在此处列出它们并进行遍历:

AppWrapper
AppHeader
AppTitle
rotate360
AppLogo
# We're adding our own styles for
AppIntro
Underline
StyledHyperLink
Button

AppWrapper is the top level wrapper which in a larger component could be used for layout with CSS Grid or Flexbox, in our case we're going to align the text center.

AppWrapper是顶层包装器,在较大的组件中可用于CSS Grid或Flexbox进行布局,在我们的情况下,我们将对齐文本中心。

Straightforward enough, right? Now the majority of the rest of the components will use the styled-components ThemeProvider which is what we're going to pass our theme to from the Context API.

简单明了吧? 现在,其余的大多数组件将使用样式化的组件ThemeProvider ,这就是我们要从Context API传递主题的对象。

添加主题以在React Context API之间切换 (Add themes to switch between with the React Context API)

Ok, we need to define some themes to pass to the ThemeProvider, we're going to define several theme aspects we want to change, these are going to be:

好的,我们需要定义一些主题以传递给ThemeProvider ,我们将定义要更改的几个主题方面,这些方面将是:

primary; // colour
secondary; // colour
danger; // colour
fontHeader; // font
fontBody; // font

Create a file to contain the theme object in the theme directory and call it globalStyle.js and add in the following:

theme目录中创建一个包含主题对象的文件,并将其globalStyle.js并添加以下内容:

import { injectGlobal } from 'styled-components';

export const themes = {
  theme1: {
    primary: '#ff0198',
    secondary: '#01c1d6',
    danger: '#e50000',
    fontHeader: 'Old Standard TT, sans, sans-serif',
    fontBody: 'Nunito, sans-serif',
  },

  theme2: {
    primary: '#6e27c5',
    secondary: '#ffb617',
    danger: '#ff1919',
    fontHeader: 'Enriqueta, sans-serif',
    fontBody: 'Exo 2, sans, sans-serif',
  },

  theme3: {
    primary: '#f16623',
    secondary: '#2e2e86',
    danger: '#cc0000',
    fontHeader: 'Kaushan Script, sans, sans-serif',
    fontBody: 'Headland One, sans-serif',
  },
};

injectGlobal`
  @import url('
    https://fonts.googleapis.com/css?family=
    Old+Standard+TT:400,700|
    Nunito:400,700'|
    Enriqueta:400,700|
    Exo+2:400,700|
    Kaushan+Script:400,700|
    Headland+One:400,700|
  ');

  body {
    padding: 0;
    margin: 0;
  }
`;

Ok, so nothing really happening there apart from setting up the styles for use later.

好的,除了设置样式供以后使用外,实际上什么也没有发生。

You will notice that injectGlobal is being used here, this is where we're setting the fonts for use throughout the app, injectGlobal should be used once in an app to set global styles like this.

您会注意到这里使用了injectGlobal ,这是我们设置要在整个应用程序中使用的字体的地方, injectGlobal 应该在应用程序中使用一次 ,以设置这样的全局样式。

Onwards! Let us now focus on getting the basic app styles into the App.js component. We can now start using the ThemeProvider in App.js. To do this, for now, to get some visual feedback we're going to apply one of the themes from the themes object in globalStyle.js this is so, as we are adding in components we can see the theme being applied.

向前! 现在让我们集中精力将基本的应用程序样式添加到App.js组件中。 现在,我们可以开始在App.js使用ThemeProvider 。 为此,现在要获得一些视觉反馈,我们将应用globalStyle.js themes对象中的一个主题,如此,当我们添加组件时,就可以看到正在应用的主题。

We can do this now with the AppHeader which is a styled div:

我们现在可以使用样式为div的AppHeader此操作:

const AppHeader = styled.div`
  height: 12rem;
  padding: 1rem;
  color: ${({ theme }) => theme.dark};
  background-color: ${({ theme }) => theme.primary};
`;

You will notice here that we're beginning to use the styled-components, theme props but, if we paste this code in now there won't be any change until the ThemeProvider is passed the theme object so we're going to wrap App.js with the ThemeProvider component so that any component encapsulated by the ThemeProvider is able to receive theme props.

您将在此处注意到,我们开始使用样式化组件, theme道具,但是,如果现在粘贴此代码,则在将ThemeProvider传递给theme对象之前不会有任何更改,因此将包装App.jsThemeProvider组件,以便由ThemeProvider封装的任何组件都可以接收theme道具。

AppTitle is going to be a h1 so:

AppTitle将成为h1,因此:

const AppTitle = styled.h1`
  font-family: ${({ theme }) => theme.fontHeader};
`;

For the spinning React logo we can use the asset used previously in the styled-components getting started example

对于旋转的React徽标,我们可以使用以前在样式化组件入门示例中使用的资产

We can add it in with the imports at the top of the App.js component and add it into the AppLogo styled component as an img tag:

我们可以将其添加到App.js组件顶部的App.js ,并将其作为img标签添加到AppLogo样式的组件中:

const logo = `https://user-images.githubusercontent.com/
    234708/37256552-32635a02-2554-11e8-8fe3-8ab5bd969d8e.png`;

The keyframes helper will need to be imported alongside the ThemeProvider for the animation on the react logo.

keyframes帮助器将需要与ThemeProvider一起导入,以用于react徽标上的动画。

const rotate360 = keyframes`
  from { 
    transform: rotate(0deg); 
  }
  to { 
    transform: rotate(360deg); 
  }
`;

const AppLogo = styled.img`
  animation: ${rotate360} infinite 5s linear;
  height: 80px;
  &:hover {
    animation: ${rotate360} infinite 1s linear;
  }
`;

共享组件 (Shared components)

Shared components are covered in the styled-components getting started guide if you need more information, for this example we're going to bring in the final couple of components as shared ones for the StyledHyperLink and Button in src/Shared.js add the following:

如果您需要更多信息,则样式化的组件入门指南中介绍了共享的组件,在本示例中,我们将引入最后两个组件,作为src/Shared.jsStyledHyperLinkButton共享组件。 :

src/Shared.js

src/Shared.js

import styled, { css } from 'styled-components';

export const Button = styled.button`
  padding: 0.5rem 1rem;
  margin: 0.5rem 1rem;
  color: ${({ theme }) => theme.primary};
  font-size: 1rem;
  box-shadow: 0 3px 5px rgba(0, 0, 0, 0.1);
  cursor: pointer;
  border: 2px solid ${props => props.border};
  background-color: Transparent;
  text-transform: uppercase;
  border-radius: 4px;
  transition: all 0.1s;
  &:hover {
    transform: translateY(1px);
    box-shadow: 0 2px 3px rgba(0, 0, 0, 0.15);
  }
  ${props =>
    props.primary &&
    css`
      background: ${({ theme }) => theme.primary};
      border: 2px solid ${({ theme }) => theme.primary};
      color: white;
    `};
  ${props =>
    props.danger &&
    css`
      background: ${({ theme }) => theme.danger};
      border: 2px solid ${({ theme }) => theme.danger};
      color: white;
    `};
  &:hover {
    transform: translateY(2px);
    box-shadow: 0 2px 3px rgba(0, 0, 0, 0.15);
  }
`;

export const StyledHyperLink = styled.a`
  cursor: pointer;
  &:visited,
  &:active {
    color: ${({ theme }) => theme.primary};
  }
  &:hover {
    color: ${({ theme }) => theme.secondary};
  }
  color: ${({ theme }) => theme.primary};
`;

Then import the components like any other:

然后像其他导入组件一样导入:

The last three components for now, AppIntro, Underline and StyledHyperLink:

现在,最后三个组件是AppIntroUnderlineStyledHyperLink

const AppIntro = styled.p`
  color: ${({ theme }) => theme.dark};
  font-size: large;
  code {
    font-size: 1.3rem;
  }
  font-family: ${({ theme }) => theme.fontBody};
`;

const Underline = styled.span`
  border-bottom: 4px solid ${({ theme }) => theme.secondary};
`;

const StyledHyperLink = SHL.extend`
  text-decoration: none;
  font-family: ${({ theme }) => theme.fontBody};
  color: ${({ theme }) => theme.fontDark};
`;

Add them in under the AppLogo styled component and then we can add the rest of the components into the App function return, so, ready for another copy pasta? Here:

将它们添加到AppLogo样式的组件下,然后我们可以将其余组件添加到App函数return ,因此,准备好其他复制面食了吗? 这里:

<AppIntro>
  Bootstrapped with{' '}
  <Underline>
    <code>
      <StyledHyperLink
        href={`https://github.com/facebook/create-react-app`}
        target="_blank"
        rel="noopener"
      >
        create-react-app
      </StyledHyperLink>
    </code>
  </Underline>.
</AppIntro>
<AppIntro>
  Components styled with{' '}
  <Underline>
    <code>
      <StyledHyperLink
        href={`https://www.styled-components.com`}
        target="_blank"
        rel="noopener"
      >
        styled-components
      </StyledHyperLink>
    </code>
  </Underline>{' '}
  <span role="img" aria-label="nail polish">
    ?
  </span>
</AppIntro>
<AppIntro>
  Fonts picked with{' '}
  <Underline>
    <code>
      <StyledHyperLink
        href={`https://fontjoy.com/`}
        target="_blank"
        rel="noopener"
      >
        fontjoy.com
      </StyledHyperLink>
    </code>
  </Underline>
</AppIntro>
<Button>Normal Button</Button>
<Button primary>Primary Button</Button>
<Button danger>Danger Button</Button>

Sorry for the code wall! Right paste that in under the closing </AppHeader> tag and we should have the base of what we're going to theme!

对不起,代码墙! 右键将其粘贴在结束的</AppHeader>标签下,我们应该以主题为基础!

Ok? How's it looking?

好? 看起来怎么样

Now we have a basic React app that uses styled-components!

现在我们有了一个使用样式组件的基本React应用!

使用React Context API (Use the React Context API)

Now for the main event! Here we're going to cover:

现在是主要事件! 这里我们将介绍:

Making the theme context.

使主题上下文。

Using the context API with a component.

结合使用上下文API和组件。

Consuming the Context API in multiple components.

在多个组件中使用Context API。

So, passing state needlessly through components is what we can use the Context API to avoid. If we take a look at the styled-components getting started example we can see the state being managed in the App.js component and the handleThemeChange function has to be passed to the ThemeSelect component much the same way as any props would need to be passed down. That is a simplified example but it's quite easy to imagine if that component lived on a footer component or a menu item there would be several other components that would need to have the state passed through them that would not actually need that state or props. Make sense?

因此,可以通过Context API避免不必要地通过组件传递状态。 如果我们看一看的风格组件入门例子 ,我们可以看到在被管理的状态App.js组件和handleThemeChange功能将被传递到ThemeSelect成分几乎相同的方式为任何道具都需要传递下。 这是一个简化的示例,但是很容易想象,如果该组件位于页脚组件或菜单项上,那么将有几个其他组件需要通过它们的状态,而实际上并不需要该状态或道具。 合理?

example

<App>               {/* state begins here */}
  <Header>          {/* through here */}
    <Navigation>    {/* and here */}
      <ThemeSelect> {/* to be used here */}
    </Navigation>
  </Header>
  <Footer/>
</App>

添加网站主题上下文 (Add the site theme context)

In our src/contexts/ directory we're going to make our SiteThemeContext.js, import React and define and export our context:

在我们的src/contexts/目录中,我们将制作SiteThemeContext.js ,导入React并定义并导出上下文:

import React from 'react';

export const SiteThemeContext = React.createContext();

那么上下文是什么? (So what is a context?)

A context is made up of two things, a provider and a consumer, you have a single provider which will sit up as high as possible in the component tree so that multiple consumers can get the state and props from the provider.

上下文由一个提供程序和一个使用者两部分组成,您有一个提供程序,它将在组件树中位于最高位置,以便多个使用者可以从提供程序获取状态和支持。

Hopefully you recall the point at which we abstracted the function App component out of the src/index.js file, this is so we could add in the context provider at the highest level of the app, in the src/index.js file. This means that any consumer within the app, no matter how deep into the component tree it is, it can get the state and props from that top level.

希望您记得从src/index.js文件中抽象出function App组件的那一点,这样我们可以在src/index.js文件的应用程序的最高级别中添加上下文提供程序。 这意味着应用程序中的任何使用者,无论它在组件树中的深度如何,都可以从该顶层获取状态和道具。

Now to create a provider, the provider is a regular React component, so:

现在创建提供程序,该提供程序是常规的React组件,因此:

import React from 'react'

export const SiteThemeContext = React.createContext()

export class SiteThemeProvider extends React.Component {
  render() {
    return (
      <SiteThemeContext.Provider value={}>
        {this.props.children}
      </SiteThemeContext.Provider>
    )
  }
}

What is being returned by <SiteThemeProvider> is the <SiteThemeContext.Provider> and the children of that component, the one prop you have to provide the the provider is a value prop. This is the variable that the consumer has access to. The consumer being <SiteThemeContext.Consumer> (more on this shortly).

<SiteThemeContext.Provider><SiteThemeProvider>返回的是该组件的子代,提供者必须提供的一个支持就是value支持。 这是使用者可以访问的变量。 使用者为<SiteThemeContext.Consumer> ( <SiteThemeContext.Consumer>详细介绍)。

So what we can do now is have what is passed into value be an object value={{}} so it can store multiple properties of the state and the functions that are defined in SiteThemeContext.

因此,我们现在所要做的就是将value传递给对象value={{}}以便它可以存储状态的多个属性以及SiteThemeContext中定义的SiteThemeContext

The state for the context needs to be the theme so we need to import the theme from src/theme/globalStyle and add that to the state, we're going to default the theme (and state) to theme1 and add a copy of that into the value prop by spreading into state ...❤️, it should look like this:

上下文的状态必须是theme因此我们需要从src/theme/globalStyle导入主题并将其添加到状态,我们将默认主题(和状态)为theme1并添加该主题的副本通过传播到状态...❤️进入valueStruts,它应该像这样:

import React from 'react';
import PropTypes from 'prop-types';

import { themes } from '../theme/globalStyle';

export const SiteThemeContext = React.createContext();

export class SiteThemeProvider extends React.Component {
  state = {
    theme: themes['theme1'],
  };

  render() {
    return (
      <SiteThemeContext.Provider
        value={{
          ...this.state,
        }}>
        {this.props.children}
      </SiteThemeContext.Provider>
    );
  }
}

Ok, it's been a while since I've added a gif, time for another one!

好的,自从我添加了gif以来已经有一段时间了,是时候再来一个了!

And bring in the themes and add state:

并引入themes并添加状态:

Now we can add in a function to the provider to change the theme state based on what has been selected via the handleThemeChange event value:

现在,我们可以向提供程序中添加一个函数,以根据通过handleThemeChange事件值选择的内容更改主题状态:

handleThemeChange = e => {
  const key = e.target.value;
  const theme = themes[key];
  this.setState({ theme });
};

This can then be consumed by any provider that wants to use it, we're going to need to add it into the value prop, like this:

然后,任何想要使用它的提供程序都可以使用它,我们将需要将其添加到value属性中,如下所示:

import React from 'react';
import PropTypes from 'prop-types';

import { themes } from '../theme/globalStyle';

export const SiteThemeContext = React.createContext();

export class SiteThemeProvider extends React.Component {
  state = {
    theme: themes['theme1'],
  };

  handleThemeChange = e => {
    const key = e.target.value;
    const theme = themes[key];
    this.setState({ theme });
  };

  render() {
    return (
      <SiteThemeContext.Provider
        value={{
          ...this.state,
          handleThemeChange: this.handleThemeChange,
        }}>
        {this.props.children}
      </SiteThemeContext.Provider>
    );
  }
}

Ok, that is the site theme context component covered, pretty straight forward, right?

好的,这是网站主题上下文组件,很简单,对吧?

What I should mention is that the e in the handleThemeChange function is going to be the event from the theme select box that we're about to make.

我应该提到的是, handleThemeChange函数中的e将成为我们将要创建的主题选择框中的事件。

Let's go through adding in the function and adding that to the state:

让我们来看一下添加函数并将其添加到状态:

And now we can add the theme provider to src/index.js so anything lower in the dependency tree can access it via a consumer.

现在,我们可以将主题提供程序添加到src/index.js以便依赖项树中任何较低的内容都可以通过使用者访问它。

添加主题选择 (Add the theme select)

Now we want a want to call the handleThemeChange function that is part of the SiteThemeProvider via the SiteThemeContext! I'm sure this all making perfect sense right now (?) so let's get right in there and define the component that we're going to use to consume the SiteThemeContext.Provider with a ThemeSelect component!

现在,我们希望有一个要调用的handleThemeChange功能是一部分SiteThemeProvider通过SiteThemeContext ! 我确定这一切现在都非常SiteThemeContext.Provider (?),所以让我们进入那里,定义一个我们将用来通过ThemeSelect组件使用ThemeSelect组件!

In the src/components directory add a new ThemeSelect.js component, this is where we are going to consume the site theme context with a consumer.

src/components目录中,添加一个新的ThemeSelect.js组件,这是我们要与使用者一起使用网站主题上下文的地方。

The child of a consumer isn't a component it's a function, so what we're going to need to do is have the theme select inside the return of that function.

消费者的子代不是一个组件,而是一个函数,因此我们需要做的就是在该函数的返回中选择主题。

Let's first set up the styled-components that will make up the select, which is a select box, some options and a wrapper.

让我们首先设置将构成选择的样式化组件,它是一个选择框,一些选项和一个包装器。

First we'll do it without the consumer then we'll add it in.

首先,我们将在没有使用者的情况下进行操作,然后将其添加进来。

ThemeSelect.js

ThemeSelect.js

import React from 'react';
import styled from 'styled-components';

import { themes } from '../theme/globalStyle';

const SelectWrapper = styled.div`
  margin: 0rem 0.5rem 0rem 0.25rem;
  padding: 0rem 0.5rem 0rem 0.25rem;
`;

const Select = styled.select`
  margin: 1.5rem 0.5rem;
  padding: 0.25rem 0.5rem;
  font-family: ${({ theme }) => theme.fontBody};
  border: 2px solid ${({ theme }) => theme.secondary};
  box-shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.1);
  background: ${({ theme }) => theme.foreground};
  border-radius: 4px;
`;

export const SelectOpt = styled.option`
  font-family: ${({ theme }) => theme.fontBody};
`;

const ThemeSelect = props => {
  return (
    <SelectWrapper>
      <Select>
        {Object.keys(themes).map((theme, index) => {
          return (
            <SelectOpt key={index} value={theme}>
              Theme {index + 1}
            </SelectOpt>
          );
        })}
      </Select>
    </SelectWrapper>
  );
};

export default ThemeSelect;

So from this we can list the this themes available to us in the themes object. But that's it, the function to handle the theme change lives on the SiteThemeProvider.

因此,我们可以在themes对象中列出可供我们使用的themes 。 就是这样,处理主题更改的功能SiteThemeProvider存在于SiteThemeProvider

Back to the SiteThemeContext.Consumer as I mentioned earlier the child of a consumer is a function () => () the first section is the value from the provider (<SiteThemeContext.Provider>) so let's take a quick look at what we've previously defined in the provider:

回到我前面提到的SiteThemeContext.Consumer ,消费者的子对象是一个函数() => () ,第一部分是提供者( <SiteThemeContext.Provider> )的value ,所以让我们快速看一下在提供者中先前定义的:

value={{
  ...this.state,
  handleThemeChange: this.handleThemeChange
}}

Available from SiteThemeContext.Provider is the state and a function so any of those items we can extract and pass to the provider, or to put it another way the consumer can access those values.

可从SiteThemeContext.Provider是状态和函数,因此我们可以提取并传递给提供者的任何项目,或者换句话说,消费者可以访问这些值。

Here we can use destructuring to pull the handleThemeChange function we need to change the theme.

在这里,我们可以使用解构来拉动我们需要更改主题的handleThemeChange函数。

import React from 'react'

import { SiteThemeContext } from '../contexts/SiteThemeContext'

const ThemeSelect = props => {
  return (
    <SiteThemeContext.Consumer>
      {({ handleThemeChange }) => ()}
    </SiteThemeContext.Consumer>
  )
}

export default ThemeSelect

Currently this isn't going to change the theme because we have that hardcoded into the styled-components ThemeProvider, what we want to do is use a consumer for the currently selected theme in the SiteThemeContext.

当前,这不会更改主题,因为我们已将其硬编码到样式化组件ThemeProvider ,我们要做的是使用一个使用者作为SiteThemeContext当前选定的主题。

Before that we'll also need to add in the onChange event we want to use to pass the event (e) to the handleThemeChange function on SiteThemeContext.

在此之前,我们还需要在添加onChange我们要使用的事件(通过事件e )到handleThemeChange的功能SiteThemeContext

Then in the App component we can import our <SiteThemeContext.Consumer> to consume the theme on the SiteThemeContext state and pass that to the styled-components ThemeProvider.

然后,在App组件中,我们可以导入<SiteThemeContext.Consumer>来使用SiteThemeContext状态上的theme ,并将其传递给样式化的组件ThemeProvider

想知道更多? (Want to know more?)

As mentioned at the start of this article a great resource is @leighchalliday and his YouTube channel where you can find his great usecase for the React Context API.

正如本文开头所提到的, @ leighchalliday 及其YouTube频道是一个很好的资源,您可以在其中找到他的出色的React Context API用

There's also the React community on spectrum and styled-components on spectrum.

在Spectrum上还有React社区,在Spectrum上还有样式组件

Example code of the walkthrough is available on CodeSandbox.

该演练的示例代码可在CodeSandbox获得

谢谢阅读 (Thanks for reading )

If there is anything I have missed, or if there is a better way to do something then please let me know.

如果我错过了任何事情,或者有更好的方法做某事,请告诉我。

Follow me on Twitter or Ask Me Anything on GitHub.

Twitter上关注我,或在GitHub上询问我

You can read other articles like this on my blog.

您可以在我的博客上阅读其他类似的文章

翻译自: https://www.freecodecamp.org/news/using-the-react-context-api-getting-started-2018/

react context

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值