¥What do I need to do to migrate to v6?
首先,我们首先将必要的软件包更新到最新版本。
¥First, let's start by updating the necessary packages to their latest versions.
如果你使用 NPM:
¥If you're using NPM:
npm install styled-components@^6.0.0 stylis@^4.0.0 npm uninstall @types/styled-components
如果你使用 Yarn:
¥If you're using Yarn:
yarn add styled-components@^6.0.0 stylis@^4.0.0 yarn remove @types/styled-components
由于样式组件现在提供了自己的类型,因此不再需要社区类型。
¥As styled-components now provides its own types, there's no longer a need for community ones.
对于 TypeScript 爱好者来说好消息 - 样式组件现在是用 TypeScript 原生编写的!即使你以前没有使用过 TypeScript,也建议你使用 TypeScript 来提高项目的可靠性,因为当你使用未知的 prop 或 prop 的值与预期不同时,它可以向你触发警报。
¥Good news for TypeScript enthusiasts – styled-components is now natively written in TypeScript! Even if you haven't used TypeScript before, it's recommended for improving the reliability of your project as it can alert you when you're using an unknown prop or if a prop has a different value than expected.
但是,如果你在项目中不使用 TypeScript,请不要担心!VS Code 等 IDE 仍会在你编写代码时获取类型并提供提示。
¥However, if you don't use TypeScript in your project, don't worry! IDEs like VS Code will still pick up the types and provide hints as you write your code.
shouldForwardProp
(shouldForwardProp
is no longer provided by default)¥shouldForwardProp
is no longer provided by default
如果尚未将样式迁移为使用 瞬态属性 ($prefix
),你可能会注意到 React 关于样式属性在 v6 中传递到 DOM 的警告。要恢复 v5 行为,请使用 StyleSheetManager
:
¥If haven't migrated your styling to use transient props ($prefix
), you might notice React warnings about styling props getting through to the DOM in v6. To restore the v5 behavior, use StyleSheetManager
:
import isPropValid from '@emotion/is-prop-valid'; import { StyleSheetManager } from 'styled-components'; function MyApp() { return ( <StyleSheetManager shouldForwardProp={shouldForwardProp}> {/* other providers or your application's JSX */} </StyleSheetManager> ) } // This implements the default behavior from styled-components v5 function shouldForwardProp(propName, target) { if (typeof target === "string") { // For HTML elements, forward the prop if it is a valid HTML attribute return isPropValid(propName); } // For other elements, forward all props return true; }
¥Vendor prefixes are omitted by default
随着网络和浏览器到 2023 年已经显着成熟,浏览器前缀通常是不必要的。因此,对于 v6 版本,我们决定默认省略自动前缀,以减少传递到页面的 CSS 量。如果你更喜欢 v5 行为,可以通过 StyleSheetManager
恢复它:
¥As the web and browsers have matured significantly by 2023, vendor prefixing is often unnecessary. Therefore, for the v6 release, we've decided to omit automatic prefixing by default to reduce the amount of CSS delivered to a page. If you prefer the v5 behavior, you can restore it via StyleSheetManager
:
import { StyleSheetManager } from 'styled-components'; function MyApp() { return ( <StyleSheetManager enableVendorPrefixes> {/* other providers or your application's JSX */} </StyleSheetManager> ) }
为了适应这一变化,原来的 disableVendorPrefixes
属性被倒置为 enableVendorPrefixes
;如果你设置了 disableVendorPrefixes
,你现在可以将其删除,因为它是新的默认值。
¥To accommodate this change, the original disableVendorPrefixes
prop was inverted to enableVendorPrefixes
; if you have disableVendorPrefixes
set, you can now remove it as it's the new default.
¥Update stylis plugins
styled-components v6 使用较新的 stylis v4;如果你提供 stylisPlugins
到 StyleSheetManager
,请确保插件是最新的。例如,stylis-plugin-rtl
发布了新版本来支持更新的 stylis。
¥styled-components v6 uses the newer stylis v4; if you are providing stylisPlugins
to StyleSheetManager
, ensure the plugins are up-to-date. For instance, stylis-plugin-rtl
released a new version to support the updated stylis.
¥Nested syntax handling
使用 stylis v4 升级 处理嵌套选择器的方式发生了变化,现在可以正确反映浏览器行为。具体来说,不以 &
开头的伪选择器(例如 :before
)将不再隐式添加 & 符号。
¥With the stylis v4 upgrade came a change to how nested selectors are handled which now correctly mirrors browser behavior. Specifically, pseudoselectors (e.g. :before
) that do not start with &
will not have the ampersand implicitly added anymore.
v5 行为
¥v5 behavior
styled.div` :hover { color: red; } ` // .[classname]:hover { color: red; } styled.div` &:hover { color: red; } ` // .[classname]:hover { color: red; }
v6 行为
¥v6 behavior
styled.div` :hover { color: red; } ` // .[classname] :hover { color: red; } (equivalent to .[classname] *:hover) styled.div` &:hover { color: red; } ` // .[classname]:hover { color: red; }
$as
和 $forwardedAs
属性已被丢弃(Transient $as
and $forwardedAs
props have been dropped)¥Transient $as
and $forwardedAs
props have been dropped
为了减少应用顺序的混乱,我们删除了瞬态 $as
和 $forwardedAs
属性。请改用常规的 as
和 forwardedAs
属性。
¥To reduce confusion around application order, we've dropped the transient $as
and $forwardedAs
props. Please use the regular as
and forwardedAs
props instead.
withComponent()
API(Dropped legacy withComponent()
API)¥Dropped legacy withComponent()
API
这种变化已经发生很长时间了。不再支持 withComponent
API,因此请改用 as
属性。你可以在定义时通过 attrs
或在运行时指定 as
:
¥This change has been a long time coming. The withComponent
API is no longer supported, so please use the as
prop instead. You can specify as
at definition time via attrs
or at runtime:
import styled from 'styled-components'; const Button = styled.button` background: blue; color: white; `; const ButtonLink = styled(Button).attrs({ as: 'a' })``; // These are equivalent, but `ButtonLink` allows for attaching further styling if desired. <Button as="a" href="https://styled-components.nodejs.cn"> <ButtonLink href="https://styled-components.nodejs.cn">
¥Minimum Node support raised to v16+
与 Node 的 维护计划 一致,我们现在支持 v16 作为仍在接收安全补丁的最旧的运行时。
¥In line with the maintenance schedule for Node, we now support v16 as the oldest runtime that's still receiving security patches.
¥What do I need to do to migrate to v5?
准备好了吗?
¥Ready for this?
npm install styled-components@^5.0.0 react@^16.8 react-dom@^16.8 react-is@^16.8
如果你使用 React Native,则至少需要 v0.59(第一个支持 hooks 的版本。)
¥If you're using React Native, you'll need at least v0.59 (the first version to support hooks.)
就是这样。💥
¥That's it. 💥
styled-components v5 没有引入任何重大的公共 API 更改,并添加了以下内容:
¥styled-components v5 does not introduce any breaking public API changes, and adds the following:
完全重写核心样式表引擎,并针对性能进行了调整
¥Total rewrite of the core stylesheet engine, tuned for performance
新的基于钩子的组件模型
¥New hooks-based component model
StyleSheetManager
有新属性:
¥StyleSheetManager
has new props:
disableCSSOMInjection
disableVendorPrefixes
stylisPlugins
尝试使用 stylis-plugin-rtl
来满足你的比迪烟需求!
¥try it with stylis-plugin-rtl
for your bidi needs!
注意:v4 中已弃用的子函数对象形式 .attrs({ prop: props => {} })
语法已在 v5 中删除。使用函数形式的 attrs 而不是 .attrs(props => ({}))
(你应该已经看到控制台警告以提前进行此更新。)
¥Note: The subfunction object-form .attrs({ prop: props => {} })
syntax that was deprecated in v4 is removed in v5. Use function-form attrs instead .attrs(props => ({}))
(you should have been seeing console warnings to make this update ahead of time.)
查看 官方公告帖 了解更多信息并了解 v5 的内容!
¥Check out the official announcement post for more information and to learn about what went into v5!
¥For jest users
更新到 jest-styled-components v7:
¥Update to jest-styled-components v7:
npm install jest-styled-components@^7.0.0
@import
和 createGlobalStyle
的注意事项(Note regarding css @import
and createGlobalStyle
)¥Note regarding css @import
and createGlobalStyle
目前,我们不建议在 cGS 中使用 @import
,因为浏览器如何通过 CSSOM API 处理 @import
存在一些问题。相反,最好将它们放置在典型 <style>
标记内的核心 index.html
文件(生成的或静态的)中。
¥At this time we do not recommend using @import
within cGS due to some issues with how browsers process @import
via the CSSOM APIs. Instead it's best to place these in your core index.html
file (generated or static) within a typical <style>
tag.
¥What do I need to do to migrate to v4?
这是一个相当大的版本,在底层和 API 级别都有很多变化。随着测试版的进展,我们将尝试发布代码模组以使以下项目变得更简单。另外,如果你发现以下步骤有任何问题,请 留下建设性反馈!
¥This is a pretty big release with lots of changes both under the hood and at the API level. As the beta progresses, we will try to release codemods to make the items below simpler. Also, if you find any issues with the steps below, please leave constructive feedback!
升级到最新的样式组件:
¥Upgrade to the latest styled-components:
npm install styled-components@^4.0.0
确保你的应用使用 react
>= 16.3;在内部,如果你想尝试使用 polyfill 来支持较旧的 React 版本,我们正在使用新的 React.forwardRef
API 和新的上下文 API
¥Make sure your application is using react
>= 16.3; internally we are using the new React.forwardRef
API and new context APIs if you wish to try and polyfill for older React version support
npm install react@^16.3 react-dom@^16.3
如果你使用的是 enzyme
或其他依赖(例如 react-test-renderer
),并且你来自旧版本的 react
,则可能需要完成更多相关升级。
¥If you are using enzyme
or other dependencies like react-test-renderer
, there may be more related upgrades to complete if you are coming from an old version of react
.
如果你使用的是 .extend
API,请将组件切换为使用 styled(StyledComponent)
。
¥If you are using the .extend
API, switch your components to use styled(StyledComponent)
instead.
代码模式可用 可以加快这一过程。
¥A codemod is available to expedite this.
🚫
import styled from 'styled-components' const Component = styled.div` background: blue; color: red; ` const ExtendedComponent = Component.extend` color: green; `
✅
import styled from 'styled-components' const Component = styled.div` background: blue; color: red; ` const ExtendedComponent = styled(Component)` color: green; `
有关更多示例,请参阅 "扩展样式" 文档。
¥See the "extending styles" documentation for more examples.
如果你使用 injectGlobal
API 将全局样式添加到页面,请改用新的 createGlobalStyle
辅助组件。
¥If you were using the injectGlobal
API to add global styles to your page, use the new createGlobalStyle
helper component instead.
代码模式可用 可以加快这一过程。
¥A codemod is available to expedite this.
🚫
import { injectGlobal } from 'styled-components' injectGlobal` body { color: red; } `
✅
import { createGlobalStyle } from "styled-components" const GlobalStyle = createGlobalStyle` body { color: red; } ` // later in your app's render method <React.Fragment> <Navigation /> <OtherImportantTopLevelComponentStuff /> <GlobalStyle /> </React.Fragment>
请参阅 createGlobalStyle
的文档,了解你可以用它做的所有很酷的事情,而这些事情以前用 injectGlobal
是不可能的!
¥See the documentation for createGlobalStyle
to see all the cool stuff you can do with it that wasn't possible before with injectGlobal
!
如果你使用的是 innerRef
属性,请将其更改为普通的 ref
。
¥If you were using the innerRef
prop, change it to a normal ref
.
🚫
const Component = styled.div` background: blue; color: red; ` // later in your render method <Component innerRef={element => { this.myElement = element }}>Something something</Component>
✅
const Component = styled.div` background: blue; color: red; ` // later in your render method <Component ref={element => { this.myElement = element }}>Something something</Component>
如果你在没有 css
辅助程序的情况下在部分中使用 keyframes
组件,那么你现在需要使用该辅助程序。一般来说,在编写要插入到样式化组件中的样式部分时,请始终使用 css 助手。
¥If you're using the keyframes
component in a partial without the css
helper, you'll need to use the helper now. In general, always use the css helper when composing styling partials to be interpolated into a styled component.
🚫
import styled, { keyframes } from 'styled-components' const animation = keyframes` 0% { opacity: 0; } 100 { opacity: 1; } ` const animationRule = ` ${animation} 1s infinite alternate ` const Component = styled.div` animation: ${animationRule}; `
✅
import styled, { css, keyframes } from 'styled-components' const animation = keyframes` 0% { opacity: 0; } 100 { opacity: 1; } ` const animationRule = css` ${animation} 1s infinite alternate; ` const Component = styled.div` animation: ${animationRule}; `
如果你使用 attrs({})
并且传递给它的某些属性是函数,建议切换到新的 attrs(props => ({}))
语法,以获得更简单、更强大的组合。
¥If you're using attrs({})
and some of the attributes you pass to it is a Function, it's recommended to switch to the new attrs(props => ({}))
syntax instead for easier and more powerful composition.
🚫
import styled from 'styled-components' const Input = styled.input.attrs({ type: props => props.inputType, })` background: blue; color: red; `
✅
import styled from 'styled-components' const Input = styled.input.attrs(props => ({ type: props.inputType, }))` background: blue; color: red; `
如果你使用 TypeScript,则类型现在位于 DefinelyTyped 中:
¥If you're using TypeScript, the typings are now located in DefinitelyTyped:
npm install @types/styled-components
就是这样!除了迁移之外,我们还强烈建议你阅读新的 "as" prop
,它将在未来取代 withComponent API
。
¥That's it! Aside from migrating, we also highly recommend reading up on the new "as" prop
which is intended to replace the withComponent API
in the future.
¥Can I nest rules?
是的:嵌套是特意从 Sass 移植的一个功能。谨慎使用它是通过减少为每个元素创建显式类的需要来减轻代码负担的好方法。
¥Yes: nesting is a feature intentionally ported from Sass. Used sparingly it's a great way to lighten your code by reducing the need to create explicit classes for every element.
父组件还可以使用它来定义受影响子组件不关心的上下文约束:
¥It can also be used by parent components to define contextual constraints that aren't properly a concern of the affected children:
FirstSecondThirdFirstSecondThird
共同定位媒体查询也非常方便,因为我们可以一目了然地看到组件在任何分辨率下将如何响应。
¥It's also incredibly convenient to co-locate media queries, since we can see at a glance exactly how the component will respond at any resolution.
Hello world!
¥Can I use CSS frameworks?
将现有 CSS 框架与样式组件集成非常简单!你可以将其现有的类名称与你的组件一起使用。
¥Integrating an existing CSS framework with styled-components is really easy! You can use its existing class names alongside your components.
例如,假设你有一个现有的应用,其中有两个你想要再次使用的类:.small
和 .big
。如果你希望该类始终附加到组件,则应该使用 attrs
方法 来附加它。如果你只想在某些情况下附加它,你可以像往常一样使用 className
属性!
¥For example, imagine you have an existing app with two classes you want to use again: .small
and .big
. If you want the class to always be attached to the component, you should use the attrs
method to attach it. If you want to attach it only in some cases you can use the className
props like you always have!
如果框架有一堆需要包含在页面上的原始全局 CSS,你可以使用 createGlobalStyle
API.CSS 添加它。这对于 CSS 重置之类的事情也很有用。
¥If the framework has a bunch of raw global CSS that needs to be included on the page, you can add it using the createGlobalStyle
API. This is also useful for things like CSS resets.
请注意,对于 styled-components v3 及更低版本,之前的全局样式 API 是 injectGlobal
。
¥Note that for styled-components v3 and below, the previous API for global styles was injectGlobal
.
¥How can I override styles with higher specificity?
覆盖具有高特异性的样式的方法是简单地增加你自己的样式的特异性。这可以使用 !important
来完成,但这很容易出错,而且通常不是一个好主意。
¥The way to override styles with a high specificity is to simply increase the specificity of your own styles. This could be done using !important
, but that's error prone and generally not a good idea.
我们推荐以下技术:
¥We recommend the following technique:
const MyStyledComponent = styled(AlreadyStyledComponent)` &&& { color: #BF4F74; font-weight: bold; } `
每个 &
都会被生成的类替换,因此注入的 CSS 看起来像这样:
¥Each &
gets replaced with the generated class, so the injected CSS then looks like this:
.MyStyledComponent-asdf123.MyStyledComponent-asdf123.MyStyledComponent-asdf123 { color: #BF4F74; font-weight: bold; }
重复的类将特异性提高到足以覆盖源顺序,而编写起来又不会很乏味!
¥The repeated class bumps the specificity high enough to override the source order without being very tedious to write!
¥How can I override inline styles?
内联样式始终优先于外部 CSS,因此你不能通过简单地增加特异性来覆盖它。
¥Inline styles will always take precedence over external CSS, so you cannot override it by simply increasing specificity.
然而,有一个巧妙的技巧,即将样式 element-attr
CSS 选择器与 !important
结合使用:
¥There is a neat trick however, which is to use the style element-attr
CSS Selector in conjunction with !important
:
const MyStyledComponent = styled(InlineStyledComponent)` &[style] { font-size: 12px !important; color: blue !important; } `
¥Why do my DOM nodes have two classes?
每个节点实际上有两个类连接到它:一个是每个组件静态的,这意味着样式化组件的每个元素都有这个类。它没有任何附加的风格。相反,它用于快速识别 DOM 对象属于哪个样式组件或在 DevTools 中进行细微更改。它也用于 组件选择器。静态类可能看起来像这样:.sc-fVOeaW
。
¥Each node actually has two classes connected to it: one is static per component, meaning each element of a styled component has this class. It hasn't any style attached to it. Instead, it's used to quickly identify which styled component a DOM objects belongs to or to make minor changes in the DevTools. It's also used for component selectors. The static class probably will look something like: .sc-fVOeaW
.
另一个是动态的,这意味着根据插值的结果,具有不同属性的样式组件的每个元素都会有所不同。它可能看起来像 .fVOeaW
(注意缺少 "sc" 前缀。)
¥The other is dynamic, meaning it will be different for every element of your styled component with different props, based on what the interpolations result in. It will probably look like .fVOeaW
(note the lack of "sc" prefix.)
例如,样式化组件 <Button />
每次都会使用相同的静态类进行渲染。如果使用插值来更改样式,例如 <Button secondary />
,则动态类将是不同的,而静态类将保持不变。
¥For example, the styled component <Button />
would render with the same static class every time. If the styles are changed using interpolations, like <Button secondary />
, then the dynamic class will be a different one, while the static class would remain the same.
¥When to use attrs?
你可以使用 attrs 将属性传递给样式组件,但这样做并不总是明智的。
¥You can pass in attributes to styled components using attrs, but it is not always sensible to do so.
经验法则是,当你希望样式化组件的每个实例都具有该属性时,请使用 attrs
;当每个实例都需要不同的属性时,请直接使用 传递属性:
¥The rule of thumb is to use attrs
when you want every instance of a styled component to have that prop, and pass props directly when every instance needs a different one:
const PasswordInput = styled.input.attrs(props => ({ // Every <PasswordInput /> should be type="password" type: "password" }))`` // This specific one is hidden, so let's set aria-hidden <PasswordInput aria-hidden="true" />
对于可以根据另一个属性的 "mode" 推断的属性也是如此。在这种情况下,你可以将 attrs
上的属性设置为根据其他 props 计算该 prop 的函数。
¥The same goes for props that can be inferred based on the "mode" of another prop. In this case you can set a property on attrs
to a function that computes that prop based on other props.
styled-components
与我的库打包在一起吗?(I am a library author. Should I bundle styled-components
with my library?)¥I am a library author. Should I bundle styled-components
with my library?
如果你是库作者,我们建议你不要将 styled-components
模块与你的库打包和发布。要实现此目标,你需要执行两个步骤:
¥If you are a library author, we recommend that you should not bundle and ship styled-components
module with your library. There are two steps that you need to do to achieve this:
在包依赖中将 styled-components
标记为外部
¥Marking styled-components
as external in your package dependencies
从你的库包中删除 styled-components
¥Removing styled-components
from your library bundle
styled-components
标记为外部(Marking styled-components
as external in your package dependencies)¥Marking styled-components
as external in your package dependencies
为此,你需要将其从 dependencies
移动到 devDependencies
并将其包含在 package.json
文件的 peerDependencies
列表中:
¥To do this, you will need to move it from dependencies
to devDependencies
and include it in the peerDependencies
list in your package.json
file:
{ - "dependencies" : { + "devDependencies" : { "styled-components": "^3.4.9" }, + "peerDependencies" : { + "styled-components": ">= 3" + } }
将 styled-components
移动到 devDependencies
将保证它不会与你的库一起安装(安装库时 npm install
或 yarn add
将忽略 devDependencies
)。
¥Moving styled-components
to devDependencies
will guarantee that it wouldn't be installed along with your library (npm install
or yarn add
will ignore devDependencies
when a library is installed).
将 styled-components
添加到 peerDependencies
将向你的库使用者触发信号,表明库中不包含 styled-components
,他们需要自行安装。
¥Adding styled-components
to peerDependencies
will signal your library consumers that styled-components
is not included with the library and they need to install it themselves.
另请注意,在 peerDependencies
部分中,版本字符串已变为更宽松的 >= 3
。这允许样式组件的未来版本自动工作,如果最终添加了重大更改,你可以通过对库进行补丁更新来简单地缩小范围。
¥Also, note that in the peerDependencies
section the version string has been made a more permissive >= 3
. This allows future versions of styled-components to work automatically and you can simply narrow the range with a patch update to your library if a breaking change is eventually added.
styled-components
(Removing styled-components
from your library bundle)¥Removing styled-components
from your library bundle
如果你在发货前打包了库,请确保没有将 styled-components
与它打包在一起。以下是如何使用一些流行的模块打包工具执行此操作的一些示例:
¥If you are bundling your library before shipping it, make sure that you are not bundling styled-components
along with it. Here are some examples of how to do this with some popular module bundling tools:
¥With Microbundle
如果你使用的是 微束,它将自动处理此步骤。Microbundle 将 peerDependencies
列表中的每个依赖视为外部依赖,并将其从构建中排除。
¥If you are using Microbundle, it will handle this step automatically. Microbundle treats every dependency in the peerDependencies
list as external and excludes it from the build for you.
¥With Rollup.js
如果你使用 Rollup.js,则应在配置中提供 external
选项:
¥If you are using Rollup.js, you should provide an external
option in your config:
export default { entry: "my-awesome-library.js", + external: [ + "styled-components" + ] }
另一种方法是使用 rollup-plugin-peer-deps-external 插件,它会自动将 peerDependencies
添加到 external
选项数组中。
¥Another approach is to use the rollup-plugin-peer-deps-external plugin which will automatically add the peerDependencies
in the external
option array for you.
+ import peerDepsExternal from 'rollup-plugin-peer-deps-external'; export default { entry: "my-awesome-library.js", + plugins: [ + // Preferably set as first plugin. + peerDepsExternal(), + ] }
¥With Webpack
如果你使用 Webpack,则应在配置中提供 externals
选项:
¥If you are using Webpack, you should provide an externals
option in your config:
modules.export = { entry: "my-awesome-library.js", + externals: { + "styled-components": { + commonjs: "styled-components", + commonjs2: "styled-components", + amd: "styled-components", + }, + }, }
你可以在 Webpack 文档的 "创作库" 部分找到有关如何将库与 Webpack 打包在一起的更多有用信息。
¥You can find more useful information on how to bundle a library with Webpack at "Authoring Libraries" section of Webpack documentation.
¥Why am I getting a warning about several instances of module on the page?
如果你在控制台中看到如下所示的警告消息,则页面上可能已初始化了多个 styled-components
实例。
¥If you are seeing a warning message in the console like the one below, you probably
have several instances of styled-components
initialized on the page.
It looks like there are several instances of "styled-components" initialized in this application. This may cause dynamic styles not rendering properly, errors happening during rehydration process and makes you application bigger without a good reason. If you are using a building tool like webpack, consider checking your bundle for duplication of the "styled-components" module.
如果你使用服务器端渲染,这可能会导致动态样式无法正常工作,甚至在补水期间出现错误。
¥This may cause dynamic styles not working properly or even errors during rehydration if you are using server-side rendering.
¥Possible reasons
发生这种情况有几个常见原因:
¥There are several common reasons for this to happen:
你有多个使用 styled-components
的应用在同一页面上运行(例如,webpack 中的多个入口点加载在同一页面上)
¥You have several applications that are using styled-components
running on the same page
(e.g., several entry points in webpack are loaded on the same page)
你的依赖中有另一个 styled-components
库
¥You have another styled-components
library somewhere in your dependencies
你的项目有一个 monorepo 结构(例如 lerna、yarn 工作区),并且 styled-components
模块是多个包的依赖(这个包或多或少与前一个包相同)
¥You have a monorepo structure for your project (e.g, lerna, yarn workspaces) and styled-components
module is a dependency in more than one package (this one is more or less the same as the previous one)
¥Running multiple applications on one page
如果你在一个页面上运行多个应用,请考虑为所有这些应用使用一个 styled-components
模块。如果你使用 webpack,则可以使用 CommonsChunkPlugin 创建 显式库块,其中将包含 styled-components
模块:
¥If you have several applications running on one page, consider using one styled-components
module for all of them. If you are using webpack, you can use CommonsChunkPlugin
to create an explicit vendor chunk,
that will contain the styled-components
module:
module.exports = { entry: { + vendor: ["styled-components"], app1: "./src/app.1.js", app2: "./src/app.2.js", }, plugins: [ + new webpack.optimize.CommonsChunkPlugin({ + name: "vendor", + minChunks: Infinity, + }), ] }
node_modules
中的重复模块(Duplicated module in node_modules
)¥Duplicated module in node_modules
如果你认为问题出在依赖中某处重复的 styled-components
模块中,有多种方法可以检查这一点。你可以在应用文件夹中使用 npm ls styled-components
、yarn list --pattern styled-components
或 find -L ./node_modules | grep /styled-components/package.json
命令。
¥If you think that the issue is in duplicated styled-components
module somewhere in your dependencies, there are several ways to check this. You can use npm ls styled-components
, yarn list --pattern styled-components
or find -L ./node_modules | grep /styled-components/package.json
commands in your application folder.
如果这些命令均未识别出重复项,请尝试分析你的打包包中是否存在 styled-components
的多个实例。你可以只检查你的打包包源,或者使用 source-map-explorer 或 webpack-bundle-analyzer 等工具。
¥If none of these commands identified the duplication, try analyzing your bundle for multiple instances of styled-components
. You can just check your bundle source, or use a tool like source-map-explorer
or webpack-bundle-analyzer.
如果你发现重复是你遇到的问题,你可以尝试通过以下几种方法来解决它:
¥If you identified that duplication is the issue that you are encountering there are several things you can try to solve it:
如果你使用的是 npm
,你可以尝试运行 npm dedupe
。此命令搜索本地依赖,并尝试通过将公共依赖进一步移到树上来简化结构。
¥If you are using npm
you can try running npm dedupe
. This command searches the local dependencies and tries to simplify the structure by moving common dependencies further up the tree.
请注意,npm dedupe
不适用于符号链接文件夹(即,当你使用 npm link
时)
¥Be aware that npm dedupe
doesn't work well with symlinked folders (i.e., when you use npm link
)
如果你使用的是 webpack,你可以更改 resolve 和 styled-components
模块的方式。你可以覆盖 webpack 查找依赖的默认顺序,并使你的应用 node_modules
比默认节点模块解析顺序更优先:
¥If you are using webpack, you can change the way it will resolve
the styled-components
module. You can overwrite the default order in which webpack will look for your dependencies and make your application node_modules
more prioritized than default node module resolution order:
resolve: { + alias: { + "styled-components": path.resolve(appFolder, "node_modules", "styled-components"), + } }
¥Usage with Lerna
要使样式化组件在 Lerna monorepo 中跨包运行,一种可能的修复方法是对 monorepo 文件的根共享 hoist 依赖。尝试使用 --hoist 标志运行引导选项。
¥One possible fix to get styled-components to run in a Lerna monorepo across packages, is to hoist shared dependencies to the root of your monorepo file. Try running the bootstrap option with the --hoist flag.
lerna bootstrap --hoist
或者,你可以从 package.json
文件中删除 styled-components
并将其手动提升到顶层 package.json 文件。
¥Alternatively, you can remove styled-components
from your package.json
file and hoist it manually to your top-level package.json file.
Lerna 根文件夹中的 package.json 文件示例
¥Example of a package.json file in a Lerna root folder
{ "name": "my-styled-monorepo", "devDependencies": { "lerna": "3.6.0" }, "dependencies": { "styled-components": "3.4.5" }, "scripts": { "bootstrap": "lerna bootstrap", "clean": "lerna clean", "start": "lerna run start", "build": "lerna run build" } }
¥Why should I avoid declaring styled components in the render method?
通过在 React 组件的 render 方法中声明样式组件,你可以在每次渲染时动态创建一个新组件。这意味着 React 将不得不在每次后续渲染时丢弃并重新计算 DOM 子树的该部分,而不是仅仅计算它们之间发生变化的差异。这会导致性能瓶颈和不可预测的行为。
¥By declaring a styled component inside the render method of a react component, you are dynamically creating a new component on every render. This means that React will have to discard and re-calculate that part of the DOM subtree on each subsequent render, instead of just calculating the difference of what changed between them. This leads to performance bottlenecks and unpredictable behavior.
🚫
const Header = () => { const Title = styled.h1` font-size: 10px; ` return ( <div> <Title /> </div> ) }
✅
const Title = styled.h1` font-size: 10px; ` const Header = () => { return ( <div> <Title /> </div> ) }
¥Why am I getting HTML attribute warnings?
下面的警告消息表明非标准属性被附加到 HTML DOM 元素,例如 <div>
或 <a>
。如果你看到此警告消息,则你或你正在使用的库可能正在将 props 作为属性附加到 HTML DOM 元素。
¥The warning message below indicates that non-standard attributes are being attached to
HTML DOM elements such as <div>
or <a>
. If you are seeing this warning message, it is likely that you or a library you are using is attaching props as attributes to HTML DOM elements.
Warning: Received "true" for a non-boolean attribute
如果你看到此警告,你可能正在通过 true
,其中 "true"
是合适的。这可能来自 .attrs
属性,或者来自你传递给 styled(Component)
组件的完全不相关的 prop。
¥If you're seeing this warning you are probably passing true
where "true"
would be appropriate. It's likely that this comes from a .attrs
property, or from a completely unrelated prop that you're passing to a styled(Component)
component.
要了解有关如何传递 props 的更多信息,请参阅 本节。
¥To learn more about how props are passed, see this section.
例如:
¥For example:
const Link = props => ( <a {...props} className={props.className}> {props.text} </a> ) const StyledComp = styled(Link)` color: ${props => (props.red ? 'red' : 'blue')}; ` <StyledComp text="Click" href="https://www.styled-components.com/" red />
这将渲染:
¥This will render:
<a text="Click" href="https://www.styled-components.com/" red="true" class="[generated class]">Click</a>
React 将警告附加的非标准属性,例如 "red" 和 "text",它们对于 <a>
元素来说不是有效的 HTML 属性。
¥React will warn on non-standard attributes being attached such as "red" and "text", which are not valid HTML attributes for the <a>
element.
要解决此问题,你可以使用瞬态属性或解构属性:
¥To fix this, you can use transient props or destructure props:
¥transient props (since 5.1)
你可以使用 瞬态属性 来解决此问题:
¥You can use transient props to fix this:
const Link = ({ className, text, ...props }) => ( <a {...props} className={className}> {text} </a> ) const StyledComp = styled(Link)` color: ${props => (props.$red ? 'red' : 'blue')}; ` <StyledComp text="Click" href="https://www.styled-components.com/" $red />
¥destructure props
如果你使用 < 5.1 的版本或者无法使用瞬态属性,则可以使用参数解构来提取那些已知的样式属性:
¥If you use a version < 5.1 or if you can't use transient props, you can use argument destructuring to pull out those known styling props:
const Link = ({ className, red, text, ...props }) => ( <a {...props} className={className}> {text} </a> ) const StyledComp = styled(Link)` color: ${props => (props.red ? 'red' : 'blue')}; ` <StyledComp text="Click" href="https://www.styled-components.com/" red />
这将渲染:
¥This will render:
<a href="https://www.styled-components.com/" class="[generated class]">Click</a>
当你使用参数解构时,从 props 对象中提取的任何变量在扩展应用剩余的 props 时都不会被包含在内 (...props
);
¥When you use argument destructuring, any variables pulled out of the props object will not be included when spread-applying the remaining props (...props
);
¥Which browsers are supported?
styled-components 支持与当前 React 版本相同的浏览器集。
¥styled-components supports the same set of browsers as the current React version.
v2.x(反应 v0.14+):IE9+,所有常青浏览器
¥v2.x (React v0.14+): IE9+, all evergreen browsers
v3.x(反应 v0.14+):IE9+,所有常青浏览器
¥v3.x (React v0.14+): IE9+, all evergreen browsers
v4.x(反应 v16.3+):IE11、IE 9+(带有 Map + Set 填充),所有常青浏览器
¥v4.x (React v16.3+): IE11, IE 9+ (with Map + Set polyfills), all evergreen browsers
v5.x(反应 v16.3+):IE11,所有常青浏览器
¥v5.x (React v16.3+): IE11, all evergreen browsers
常青浏览器包括 Chrome 和 Firefox(及其衍生产品),因为无论操作系统版本如何,它们都可以更新。Edge 和 Safari 应该也可以正常工作,因为过去几年的所有版本都支持相关 API。
¥Evergreen browsers include Chrome and Firefox (and derivatives) as they can be updated regardless of operating system version. Edge and Safari should both also work fine since all versions for the last several years support the relevant APIs.
create-react-app
一起使用?(How do I use styled-components with create-react-app
?)¥How do I use styled-components with create-react-app
?
该库的基本功能应该像任何其他库一样开箱即用。
¥The basic functionality of the library should work out of the box like any other library.
但是,如果你想进行服务器端渲染或利用 styled-components babel 插件 的一些高级功能而不弹出,则需要设置 react-app-rewired
和 react-app-rewire-styled-components
。
¥However, if you want to do server-side rendering or take advantage of some of the advanced capabilities of the styled-components babel plugin without ejecting you'll need to set up react-app-rewired
and react-app-rewire-styled-components
.
npm link
或 yarn link
时的问题?(How can I fix issues when using npm link
or yarn link
?)¥How can I fix issues when using npm link
or yarn link
?
本地链接可以成为同时共同开发项目的有用工具。然而,它会造成混乱的情况,因为你的每个本地项目都可能下载了一整套开发依赖(默认情况下,打包程序更喜欢本地版本的依赖),而这些库本来是用作单例(例如 React 和 styled-components)的。
¥Local linking can be a useful tool to co-develop projects simultaneously. However, it creates chaotic situations with libraries that are meant to be used as singletons like react and styled-components since each of your local projects likely has a full set of development dependencies downloaded (and bundlers prefer local versions of dependencies by default.)
解决方案是添加别名。这是 webpack 的示例配置:
¥The solution is to add aliasing. Here's an example config for webpack:
// const path = require('path'); { resolve: { alias: { // adjust this path as needed depending on where your webpack config is 'styled-components': path.resolve('../node_modules/styled-components') } } }
这可以确保你的构建始终使用相同的库副本,即使是在符号链接的项目中也是如此。
¥This ensures that for your build the same copy of the library will always be used, even across symlinked projects.
¥Linking in an SSR SCENARIO.
如果你在具有链接组件的项目上使用 collectStyles
函数,你最终会遇到复杂的情况。基本上发生的情况是,由于 v4 新的静态上下文 API,不同的样式组件模块现在正在管理自己的要渲染的样式组件列表,从主机应用看来好像没有什么可提取的,因为没有在其中创建样式组件 它们是从链接的包范围创建的范围。
¥If you are using the collectStyles
function on a project with linked components you will end up in a complex scenario. Basically what's happening is that because of v4 new static context API different styled-component modules are now managing their own list of styled-components to render, from the host app it appears as though there's nothing to extract because no styled components have been created in that scope they were created from the linked package scope.
¥How do I solve it?
一种解决方案是向 styled-components
模块路径解析添加别名,以始终指向 'host' 应用。希望有很多库可供我们用于此示例 module-alias
。在 SSR 索引文件的最顶部添加:
¥One solution is to add an alias to the styled-components
module path resolution to always point to the 'host' application. Hopefully there are a bunch of libraries to do that we will use for this example module-alias
. At the very top of your SSR index file add:
const path = require('path'); const moduleAlias = require('module-alias'); moduleAlias.addAlias('styled-components', path.join(__dirname, '../node_modules/styled-components'));
这将告诉节点将样式组件的所有导入/需求解析为 __dirname, '../node_modules/styled-components'
¥This will tell node to resolve all import/require's of styled-components to __dirname, '../node_modules/styled-components'
¥How do I fix flickering text after server side rendering?
当使用 createGlobalStyle
或之前的 injectGlobal
等全局样式 API 时,从 DOM 中添加和删除某些样式(如 @font-face
定义)可能会导致页面上的文本短暂闪烁。这通常发生在服务器端渲染的补水阶段。我们仍在调整这些行为的工作方式,以避免长期出现该问题。
¥When using global styling APIs like createGlobalStyle
or the former injectGlobal
, adding and removing certain styles from the DOM like @font-face
definitions can cause momentary flickering of text on the page. This typically happens during the rehydration phase of server-side rendering. We're still tweaking how these behaviors work to avoid the issue long-term.
不过,font-display
CSS 规则 中有一个 CSS 解决方案来解决这个问题。通过将规则设置为 "fallback" 模式,一旦加载字体,就不会重新加载。这消除了闪烁。
¥However, there is a CSS solution to the problem in the font-display
CSS rule. By setting the rule to "fallback" mode, once a font has been loaded it will not be reloaded. This eliminates the flicker.
@font-face { font-family: 'Foo'; src: url('/path/to/foo.woff') format('woff'); font-style: normal; font-weight: 400; font-display: fallback; /* <- this can be added to each @font-face definition */ }
styled-components/native
的声明?(Missing Declarations for styled-components/native
?)¥Missing Declarations for styled-components/native
?
如果你收到错误消息:
¥If you're getting the error message:
Could not find a declaration file for module 'styled-components/native'
在使用 TypeScript 的 React Native 项目中,是因为需要添加 @types/styled-components-react-native
。
¥In a React Native project using TypeScript, it is because you need to add @types/styled-components-react-native
.