Gatsby / GraphQL 应用程序 - 部署时的渲染和样式问题(Netlify 和 Surge)
Gatsby / GraphQL App - Rendering and Style Issues When Deployed (Netlify and Surge)
使用 styled components
使用 Gatsby
/ GraphQL
构建了一个投资组合页面。在我的本地机器上,它的外观和功能完全符合我的要求。部署后,似乎存在按钮样式问题,并且我的其中一张图片根本没有呈现。我尝试在 Netlify
和 Surge.sh
上部署,但两次的结果相同。我做错了什么? 编辑: 我的按钮样式会受到如何使用 Link
的影响吗?
以下是我的按钮样式在本地的外观:
这是部署后的样子('View Repo' 甚至无法部署):
我的 'About Me' 本地部分(2 列):
我的 'About Me' 部分已部署(仅显示第 1 列):
盖茨比-config.js
module.exports = {
siteMetadata: {
title: `Portfolio`,
description: `Lorem ipsum.`,
author: `@jordanwhunter`,
},
plugins: [
`gatsby-plugin-react-helmet`,
`gatsby-plugin-image`,
`gatsby-plugin-styled-components`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/assets/images`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `videos`,
path: `${__dirname}/src/assets/videos`,
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `gatsby-starter-default`,
short_name: `starter`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#663399`,
display: `minimal-ui`,
icon: `src/assets/images/memoji.jpeg`, // This path is relative to the root of the site.
},
},
`gatsby-plugin-gatsby-cloud`,
`gatsby-transformer-json`,
{
resolve: `gatsby-source-filesystem`,
options: {
path: `./src/data/`,
},
},
],
}
package.json
{
"name": "gatsby-starter-default",
"private": true,
"description": "A simple starter to get up and developing quickly with Gatsby",
"version": "0.1.0",
"author": "Kyle Mathews <mathews.kyle@gmail.com>",
"dependencies": {
"babel-plugin-styled-components": "^1.12.0",
"gatsby": "^3.0.1",
"gatsby-image": "^3.0.0",
"gatsby-plugin-gatsby-cloud": "^2.0.0",
"gatsby-plugin-image": "^1.0.0",
"gatsby-plugin-manifest": "^3.0.0",
"gatsby-plugin-offline": "^4.0.0",
"gatsby-plugin-react-helmet": "^4.0.0",
"gatsby-plugin-sharp": "^3.0.0",
"gatsby-plugin-styled-components": "^4.0.0",
"gatsby-source-filesystem": "^3.0.0",
"gatsby-transformer-json": "^3.0.0",
"gatsby-transformer-sharp": "^3.0.0",
"gh-pages": "^3.1.0",
"prop-types": "^15.7.2",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-helmet": "^6.1.0",
"react-icons": "^4.2.0",
"styled-components": "^5.2.1",
"surge": "^0.22.1"
},
"devDependencies": {
"prettier": "2.2.1"
},
"keywords": [
"gatsby"
],
"license": "0BSD",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md}\"",
"start": "npm run develop",
"serve": "gatsby serve",
"clean": "gatsby clean",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/gatsbyjs/gatsby-starter-default"
},
"bugs": {
"url": "https://github.com/gatsbyjs/gatsby/issues"
}
}
Portfolio.js(按钮代码从第 226 行开始)
import React from 'react'
import { useStaticQuery, graphql } from "gatsby"
import { Button } from "./Button"
import Img from "gatsby-image"
import styled from "styled-components"
const PortfolioContainer = styled.div`
min-height: 100vh;
padding: 5rem calc((100vw - 1300px) / 2);
background: #fff;
color: #fff;
`
const PortfolioHeading = styled.div`
font-size: clamp(1.5rem, 5vw, 2.5rem);
text-align: center;
margin-bottom: 5rem;
color: #000;
`
const PortfolioImg = styled(Img)`
height: 100%;
max-width: 100%;
position: absolute;
border-radius: 10px;
filter: brightness(100%);
transition: 0.4s cubic-bezier(0.075, 0.82, 0.165, 1);
`
const PortfolioWrapper = styled.div`
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 10px;
justify-items: center;
padding: 0 2rem;
@media screen and (max-width: 1200px) {
grid-template-columns: 1fr 1fr;
}
@media screen and (max-width: 868px) {
grid-template-columns: 1fr;
}
`
const PortfolioInfo = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-content: center;
align-items: center;
justify-items: center;
padding: 0 2rem;
visibility: hidden;
opacity: 0;
transition: opacity .2s, visibility .2s;
@media screen and (max-width: 280px) {
padding: 0 1rem;
justify-content: center;
align-content: center;
}
`
const PortfolioCard = styled.div`
line-height: 2;
width: 100%;
height: 500px;
position: relative;
border-radius: 10px;
transition: 0.2s ease;
&:hover ${PortfolioInfo}{
visibility: visible;
opacity: 1;
}
&:hover ${PortfolioImg}{
filter: brightness(50%)
}
`
const TextWrap = styled.div`
display: flex;
align-items: center;
text-align: center;
position: absolute;
top: 375px;
flex-wrap: wrap;
justify-content: center;
align-content: center;
width: 87%;
`
const PortfolioTitle = styled.div`
font-weight: 400;
font-size: 1rem;
margin-left: 0.5rem;
@media screen and (max-width: 280px) {
font-size: 12px;
}
`
const PortfolioDescription = styled.div`
font-size: 1rem;
@media screen and (max-width: 280px) {
font-size: 12px;
}
`
const PortfolioTechnologies = styled.div`
font-size: 1rem;
@media screen and (max-width: 280px) {
font-size: 12px;
}
`
const ButtonLink = styled.a`
text-decoration: none;
cursor: pointer;
`
const ButtonWrap = styled.div`
display: flex;
flex-direction: row;
position: absolute;
justify-content: center;
align-content: center;
align-items: center;
width: 100%;
height: -400px;
z-index: 1;
gap: 10px;
@media screen and (max-width: 280px) {
padding: 0 1rem;
justify-content: center;
align-content: center;
}
`
const CustomButton = styled(Button)`
display: flex;
align-items: center;
position: relative;
font-size: 14px;
width: 100%;
cursor: pointer;
top: -60px;
@media screen and (max-width: 480px) {
background: none;
border: none;
padding: 0 !important;
font-family: arial, sans-serif;
color: #fff;
text-decoration: underline;
cursor: pointer;
width: 100%;
font-size: 12px;
justify-content: center;
}
`
const CustomP = styled.p`
font-size: 12px;
`
export default function Portfolio({ heading }) {
const data = useStaticQuery(graphql`
query PortfolioQuery {
allPortfolioJson {
edges {
node {
alt
button1
button2
description
name
technologies
demo
repo
img {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
}
}
}
`)
function getPortfolio(data) {
const portfolioArray = []
data.allPortfolioJson.edges.forEach((item, index) => {
portfolioArray.push(
<PortfolioCard key={index}>
<PortfolioImg
src={item.node.img.childImageSharp.fluid.src}
fluid={item.node.img.childImageSharp.fluid}
alt={item.node.alt}
/>
<PortfolioInfo>
<TextWrap>
<PortfolioTitle
css={`
margin-top: -500px;
`}
>
<strong><u>Project:</u></strong> <br />
{item.node.name}
</PortfolioTitle>
<PortfolioDescription
css={`
margin-top: -300px;
`}
>
<strong><u>Description:</u></strong> <br />
{item.node.description}
</PortfolioDescription>
<PortfolioTechnologies
css={`
margin-top: -100px;
`}
>
<strong><u>Technologies:</u></strong> <br />
{item.node.technologies}
</PortfolioTechnologies>
</TextWrap>
<ButtonWrap>
<ButtonLink
href={`${item.node.demo}`}
target="_blank"
>
<CustomButton
primary="true"
round="true"
>
{item.node.button1}
</CustomButton>
</ButtonLink>
<ButtonLink
href={`${item.node.repo}`}
target="_blank"
>
<CustomButton
primary="true"
round="true"
>
{item.node.button2}
</CustomButton>
</ButtonLink>
</ButtonWrap>
</PortfolioInfo>
</PortfolioCard>
)
})
return portfolioArray;
}
return (
<PortfolioContainer id="portfolio">
<PortfolioHeading>
{heading}
<CustomP>(Tap on Mobile)</CustomP>
</PortfolioHeading>
<PortfolioWrapper>
{getPortfolio(data)}
</PortfolioWrapper>
</PortfolioContainer>
)
};
About.js(第 2 列代码从第 137 行开始):
import React from 'react'
import { useStaticQuery, graphql } from 'gatsby';
import { GrCircleInformation, GrCode, GrDocumentImage } from "react-icons/gr";
import styled from "styled-components"
import Img from "gatsby-image"
const AboutContainer = styled.div`
width: 100%;
background: #fcfcfc;
color: #000;
padding: 5rem calc((100vw - 1300px) / 2);
height: 100%;
border-top: 1px solid gray;
border-bottom: 1px solid gray;
`
const TopLine = styled.div`
color: #077bf1;
font-size: 1rem;
padding-left: 2rem;
margin-bottom: 0.75rem;
`
const Description = styled.p`
text-align: start;
padding-left: 2rem;
margin-bottom: 4rem;
font-size: clamp(1.5rem, 5vw, 2rem);
font-weight: bold;
`
const ContentWrapper = styled.div`
display: grid;
grid-template-columns: 1fr 1fr;
padding: 0 2rem;
@media screen and (max-width: 768px) {
grid-template-columns: 1fr;
}
`
const ColumnOne = styled.div`
display: grid;
grid-template-rows: 1fr 1fr;
`
const Biography = styled.div`
padding-top: 1rem;
padding-right: 2rem;
h3 {
margin-bottom: 1rem;
font-size: 1.5rem;
font-style: italic;
}
p {
color: #3b3b3b;
}
`
const ColumnTwo = styled.div`
display: grid;
grid-template-columns: 1fr;
margin-top: 2rem;
grid-gap: 10px;
@media screen and (max-width: 500px) {
grid-template-columns: 1fr;
}
`
const Image = styled(Img)`
border-radius: 10px;
height: 100%;
margin-top: -50px;
@media screen and (max-width: 375px) {
margin-top: 0;
}
`
export default function About() {
const data = useStaticQuery(graphql`
query MyQuery {
allFile(filter: {ext: {regex: "/(jpg)|(png)|(jpeg)/"}, name: {in: ["profile-photo"]}}) {
edges {
node {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`)
return (
<AboutContainer id="about">
<TopLine>
About Me
</TopLine>
<Description>
<div css={`display: flex;`}>
<GrDocumentImage /><h4 css={`font-style: italic;`}>Resumes</h4>
</div>
<div
css={`
display: flex;
font-size: 14px;
margin-bottom: -40px;
`}
>
<p>
<a href="https://docs.google.com/document/d/162ZfqqYxwYgeaY4fk7pf3GdtVn_Kp-ONqWOVCWzIhqo/edit?usp=sharing" target="_blank">Resume 2021 (ATS Version)</a><br />
<a href="https://docs.google.com/document/d/1u87owpbLG2uoPAqvoVmkuh_LEGSJuRa69OVAYm3hELU/edit?usp=sharing" target="_blank">Resume 2021 (Styled Version)</a>
</p>
</div>
</Description>
<ContentWrapper>
<ColumnOne>
<Biography>
<div css={`display: flex;`}>
<GrCircleInformation /><h3>Brand Statement</h3>
</div>
<p>
Full stack web/software developer with an entrepreneurial spirit, and keen sense of efficiency and time management. A passionate, goal-oriented team player that strives to always write clean, precise code focused on mobile responsive themes. Maintains a problem solving, can-do attitude and exhibits consistent eagerness to learn new technologies/techniques.
</p>
</Biography>
<Biography>
<div css={`display: flex;`}>
<GrCode />
<h3>Technologies</h3>
</div>
<p>
JavaScript, React, Preact, Next, Gatsby, Svelte, Node, Express, Firebase, Vercel, MongoDB, MySQL, Handlebars, jQuery, D3, GraphQL, Material-UI, CSS3, Bootstrap, Materialize, Bulma, HTML5
</p>
</Biography>
</ColumnOne>
<ColumnTwo>
{data.allFile.edges.map((image, key) => (
<Image
key={key}
src={image.node.childImageSharp.src}
fluid={image.node.childImageSharp.fluid}
/>
))}
</ColumnTwo>
</ContentWrapper>
</AboutContainer>
)
};
检查生成的 html:
<div class="Portfolio__ButtonWrap-zwd7jb-14 boxtca">
<a href="https://filmapi.vercel.app/" target="_blank" class="Portfolio__ButtonLink-zwd7jb-13 dHdqal">
<a primary="true" round="true" class="Button-sc-1t76fnu-0 Portfolio__CustomButton-zwd7jb-15 iA-DhcJ cycuPQ">View App</a>
</a>
<a primary="true" round="true" class="Button-sc-1t76fnu-0 Portfolio__CustomButton-zwd7jb-15 iA-DhcJ cycuPQ">
<a primary="true" round="true" class="Button-sc-1t76fnu-0 Portfolio__CustomButton-zwd7jb-15 iA-DhcJ cycuPQ">View Repo</a>
</a>
</div>
观察 #1:
- 第二个按钮的结构错误(不是
ButtonLink
);
为什么:
- 混乱的虚拟 DOM [结果是真实的 DOM];
可能原因:
- 多个,同类 children rendered without
key
prop(最常见的不良 React 渲染原因?);
解决方案 #1:始终对 lists/arrays/groups!
的 [元素] 使用 key
属性
'About me' 缺失列问题:
观察#2:
- 在(第一次渲染时)和 [图像] 加载期间 html/DOM 结构正常;
React 更新(重新渲染)中断 child div [of AboutContainer
] - 没有使用 key
(然后 VDOM 中的多个 div 没有唯一标识符) , 结果 - 更新破坏了内容结构。
但这不是唯一的原因 - 真正的原因是使用基于 <Img/>
的组件 - 对于新的 gatsby 图像插件[版本]来说已经过时了。
解决方案 #2:
您应该使用 <GatsbyImage/>
个组件。
始终确保您引用的文档是最新的!
graphql
和使用 gatsby-plugin-image
中的 GatsbyImage
/ StaticImage
组件而不是 [=15 中的 Img
组件,语法发生了重大变化=].
要修复 Portfolio.js
- 图像渲染影响了按钮链接 - 必须重构代码以适应当前引用 gatsby-plugin-image
中的 GatsbyImage
组件的语法。 graphql
和 useStaticQuery
语法也必须重构。如需更多信息,请访问 Gatsby's documentation (thanks to @xadm 为我指明正确的方向)。
About.js
也通过更新语法修复了...除了这个 Img
标记更改为 StaticImage
并且 graphql
和 useStaticQuery
被完全删除.
使用 styled components
使用 Gatsby
/ GraphQL
构建了一个投资组合页面。在我的本地机器上,它的外观和功能完全符合我的要求。部署后,似乎存在按钮样式问题,并且我的其中一张图片根本没有呈现。我尝试在 Netlify
和 Surge.sh
上部署,但两次的结果相同。我做错了什么? 编辑: 我的按钮样式会受到如何使用 Link
的影响吗?
以下是我的按钮样式在本地的外观:
这是部署后的样子('View Repo' 甚至无法部署):
我的 'About Me' 本地部分(2 列):
我的 'About Me' 部分已部署(仅显示第 1 列):
盖茨比-config.js
module.exports = {
siteMetadata: {
title: `Portfolio`,
description: `Lorem ipsum.`,
author: `@jordanwhunter`,
},
plugins: [
`gatsby-plugin-react-helmet`,
`gatsby-plugin-image`,
`gatsby-plugin-styled-components`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/assets/images`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `videos`,
path: `${__dirname}/src/assets/videos`,
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `gatsby-starter-default`,
short_name: `starter`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#663399`,
display: `minimal-ui`,
icon: `src/assets/images/memoji.jpeg`, // This path is relative to the root of the site.
},
},
`gatsby-plugin-gatsby-cloud`,
`gatsby-transformer-json`,
{
resolve: `gatsby-source-filesystem`,
options: {
path: `./src/data/`,
},
},
],
}
package.json
{
"name": "gatsby-starter-default",
"private": true,
"description": "A simple starter to get up and developing quickly with Gatsby",
"version": "0.1.0",
"author": "Kyle Mathews <mathews.kyle@gmail.com>",
"dependencies": {
"babel-plugin-styled-components": "^1.12.0",
"gatsby": "^3.0.1",
"gatsby-image": "^3.0.0",
"gatsby-plugin-gatsby-cloud": "^2.0.0",
"gatsby-plugin-image": "^1.0.0",
"gatsby-plugin-manifest": "^3.0.0",
"gatsby-plugin-offline": "^4.0.0",
"gatsby-plugin-react-helmet": "^4.0.0",
"gatsby-plugin-sharp": "^3.0.0",
"gatsby-plugin-styled-components": "^4.0.0",
"gatsby-source-filesystem": "^3.0.0",
"gatsby-transformer-json": "^3.0.0",
"gatsby-transformer-sharp": "^3.0.0",
"gh-pages": "^3.1.0",
"prop-types": "^15.7.2",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-helmet": "^6.1.0",
"react-icons": "^4.2.0",
"styled-components": "^5.2.1",
"surge": "^0.22.1"
},
"devDependencies": {
"prettier": "2.2.1"
},
"keywords": [
"gatsby"
],
"license": "0BSD",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md}\"",
"start": "npm run develop",
"serve": "gatsby serve",
"clean": "gatsby clean",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/gatsbyjs/gatsby-starter-default"
},
"bugs": {
"url": "https://github.com/gatsbyjs/gatsby/issues"
}
}
Portfolio.js(按钮代码从第 226 行开始)
import React from 'react'
import { useStaticQuery, graphql } from "gatsby"
import { Button } from "./Button"
import Img from "gatsby-image"
import styled from "styled-components"
const PortfolioContainer = styled.div`
min-height: 100vh;
padding: 5rem calc((100vw - 1300px) / 2);
background: #fff;
color: #fff;
`
const PortfolioHeading = styled.div`
font-size: clamp(1.5rem, 5vw, 2.5rem);
text-align: center;
margin-bottom: 5rem;
color: #000;
`
const PortfolioImg = styled(Img)`
height: 100%;
max-width: 100%;
position: absolute;
border-radius: 10px;
filter: brightness(100%);
transition: 0.4s cubic-bezier(0.075, 0.82, 0.165, 1);
`
const PortfolioWrapper = styled.div`
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 10px;
justify-items: center;
padding: 0 2rem;
@media screen and (max-width: 1200px) {
grid-template-columns: 1fr 1fr;
}
@media screen and (max-width: 868px) {
grid-template-columns: 1fr;
}
`
const PortfolioInfo = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-content: center;
align-items: center;
justify-items: center;
padding: 0 2rem;
visibility: hidden;
opacity: 0;
transition: opacity .2s, visibility .2s;
@media screen and (max-width: 280px) {
padding: 0 1rem;
justify-content: center;
align-content: center;
}
`
const PortfolioCard = styled.div`
line-height: 2;
width: 100%;
height: 500px;
position: relative;
border-radius: 10px;
transition: 0.2s ease;
&:hover ${PortfolioInfo}{
visibility: visible;
opacity: 1;
}
&:hover ${PortfolioImg}{
filter: brightness(50%)
}
`
const TextWrap = styled.div`
display: flex;
align-items: center;
text-align: center;
position: absolute;
top: 375px;
flex-wrap: wrap;
justify-content: center;
align-content: center;
width: 87%;
`
const PortfolioTitle = styled.div`
font-weight: 400;
font-size: 1rem;
margin-left: 0.5rem;
@media screen and (max-width: 280px) {
font-size: 12px;
}
`
const PortfolioDescription = styled.div`
font-size: 1rem;
@media screen and (max-width: 280px) {
font-size: 12px;
}
`
const PortfolioTechnologies = styled.div`
font-size: 1rem;
@media screen and (max-width: 280px) {
font-size: 12px;
}
`
const ButtonLink = styled.a`
text-decoration: none;
cursor: pointer;
`
const ButtonWrap = styled.div`
display: flex;
flex-direction: row;
position: absolute;
justify-content: center;
align-content: center;
align-items: center;
width: 100%;
height: -400px;
z-index: 1;
gap: 10px;
@media screen and (max-width: 280px) {
padding: 0 1rem;
justify-content: center;
align-content: center;
}
`
const CustomButton = styled(Button)`
display: flex;
align-items: center;
position: relative;
font-size: 14px;
width: 100%;
cursor: pointer;
top: -60px;
@media screen and (max-width: 480px) {
background: none;
border: none;
padding: 0 !important;
font-family: arial, sans-serif;
color: #fff;
text-decoration: underline;
cursor: pointer;
width: 100%;
font-size: 12px;
justify-content: center;
}
`
const CustomP = styled.p`
font-size: 12px;
`
export default function Portfolio({ heading }) {
const data = useStaticQuery(graphql`
query PortfolioQuery {
allPortfolioJson {
edges {
node {
alt
button1
button2
description
name
technologies
demo
repo
img {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
}
}
}
`)
function getPortfolio(data) {
const portfolioArray = []
data.allPortfolioJson.edges.forEach((item, index) => {
portfolioArray.push(
<PortfolioCard key={index}>
<PortfolioImg
src={item.node.img.childImageSharp.fluid.src}
fluid={item.node.img.childImageSharp.fluid}
alt={item.node.alt}
/>
<PortfolioInfo>
<TextWrap>
<PortfolioTitle
css={`
margin-top: -500px;
`}
>
<strong><u>Project:</u></strong> <br />
{item.node.name}
</PortfolioTitle>
<PortfolioDescription
css={`
margin-top: -300px;
`}
>
<strong><u>Description:</u></strong> <br />
{item.node.description}
</PortfolioDescription>
<PortfolioTechnologies
css={`
margin-top: -100px;
`}
>
<strong><u>Technologies:</u></strong> <br />
{item.node.technologies}
</PortfolioTechnologies>
</TextWrap>
<ButtonWrap>
<ButtonLink
href={`${item.node.demo}`}
target="_blank"
>
<CustomButton
primary="true"
round="true"
>
{item.node.button1}
</CustomButton>
</ButtonLink>
<ButtonLink
href={`${item.node.repo}`}
target="_blank"
>
<CustomButton
primary="true"
round="true"
>
{item.node.button2}
</CustomButton>
</ButtonLink>
</ButtonWrap>
</PortfolioInfo>
</PortfolioCard>
)
})
return portfolioArray;
}
return (
<PortfolioContainer id="portfolio">
<PortfolioHeading>
{heading}
<CustomP>(Tap on Mobile)</CustomP>
</PortfolioHeading>
<PortfolioWrapper>
{getPortfolio(data)}
</PortfolioWrapper>
</PortfolioContainer>
)
};
About.js(第 2 列代码从第 137 行开始):
import React from 'react'
import { useStaticQuery, graphql } from 'gatsby';
import { GrCircleInformation, GrCode, GrDocumentImage } from "react-icons/gr";
import styled from "styled-components"
import Img from "gatsby-image"
const AboutContainer = styled.div`
width: 100%;
background: #fcfcfc;
color: #000;
padding: 5rem calc((100vw - 1300px) / 2);
height: 100%;
border-top: 1px solid gray;
border-bottom: 1px solid gray;
`
const TopLine = styled.div`
color: #077bf1;
font-size: 1rem;
padding-left: 2rem;
margin-bottom: 0.75rem;
`
const Description = styled.p`
text-align: start;
padding-left: 2rem;
margin-bottom: 4rem;
font-size: clamp(1.5rem, 5vw, 2rem);
font-weight: bold;
`
const ContentWrapper = styled.div`
display: grid;
grid-template-columns: 1fr 1fr;
padding: 0 2rem;
@media screen and (max-width: 768px) {
grid-template-columns: 1fr;
}
`
const ColumnOne = styled.div`
display: grid;
grid-template-rows: 1fr 1fr;
`
const Biography = styled.div`
padding-top: 1rem;
padding-right: 2rem;
h3 {
margin-bottom: 1rem;
font-size: 1.5rem;
font-style: italic;
}
p {
color: #3b3b3b;
}
`
const ColumnTwo = styled.div`
display: grid;
grid-template-columns: 1fr;
margin-top: 2rem;
grid-gap: 10px;
@media screen and (max-width: 500px) {
grid-template-columns: 1fr;
}
`
const Image = styled(Img)`
border-radius: 10px;
height: 100%;
margin-top: -50px;
@media screen and (max-width: 375px) {
margin-top: 0;
}
`
export default function About() {
const data = useStaticQuery(graphql`
query MyQuery {
allFile(filter: {ext: {regex: "/(jpg)|(png)|(jpeg)/"}, name: {in: ["profile-photo"]}}) {
edges {
node {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`)
return (
<AboutContainer id="about">
<TopLine>
About Me
</TopLine>
<Description>
<div css={`display: flex;`}>
<GrDocumentImage /><h4 css={`font-style: italic;`}>Resumes</h4>
</div>
<div
css={`
display: flex;
font-size: 14px;
margin-bottom: -40px;
`}
>
<p>
<a href="https://docs.google.com/document/d/162ZfqqYxwYgeaY4fk7pf3GdtVn_Kp-ONqWOVCWzIhqo/edit?usp=sharing" target="_blank">Resume 2021 (ATS Version)</a><br />
<a href="https://docs.google.com/document/d/1u87owpbLG2uoPAqvoVmkuh_LEGSJuRa69OVAYm3hELU/edit?usp=sharing" target="_blank">Resume 2021 (Styled Version)</a>
</p>
</div>
</Description>
<ContentWrapper>
<ColumnOne>
<Biography>
<div css={`display: flex;`}>
<GrCircleInformation /><h3>Brand Statement</h3>
</div>
<p>
Full stack web/software developer with an entrepreneurial spirit, and keen sense of efficiency and time management. A passionate, goal-oriented team player that strives to always write clean, precise code focused on mobile responsive themes. Maintains a problem solving, can-do attitude and exhibits consistent eagerness to learn new technologies/techniques.
</p>
</Biography>
<Biography>
<div css={`display: flex;`}>
<GrCode />
<h3>Technologies</h3>
</div>
<p>
JavaScript, React, Preact, Next, Gatsby, Svelte, Node, Express, Firebase, Vercel, MongoDB, MySQL, Handlebars, jQuery, D3, GraphQL, Material-UI, CSS3, Bootstrap, Materialize, Bulma, HTML5
</p>
</Biography>
</ColumnOne>
<ColumnTwo>
{data.allFile.edges.map((image, key) => (
<Image
key={key}
src={image.node.childImageSharp.src}
fluid={image.node.childImageSharp.fluid}
/>
))}
</ColumnTwo>
</ContentWrapper>
</AboutContainer>
)
};
检查生成的 html:
<div class="Portfolio__ButtonWrap-zwd7jb-14 boxtca">
<a href="https://filmapi.vercel.app/" target="_blank" class="Portfolio__ButtonLink-zwd7jb-13 dHdqal">
<a primary="true" round="true" class="Button-sc-1t76fnu-0 Portfolio__CustomButton-zwd7jb-15 iA-DhcJ cycuPQ">View App</a>
</a>
<a primary="true" round="true" class="Button-sc-1t76fnu-0 Portfolio__CustomButton-zwd7jb-15 iA-DhcJ cycuPQ">
<a primary="true" round="true" class="Button-sc-1t76fnu-0 Portfolio__CustomButton-zwd7jb-15 iA-DhcJ cycuPQ">View Repo</a>
</a>
</div>
观察 #1:
- 第二个按钮的结构错误(不是
ButtonLink
);
为什么:
- 混乱的虚拟 DOM [结果是真实的 DOM];
可能原因:
- 多个,同类 children rendered without
key
prop(最常见的不良 React 渲染原因?);
解决方案 #1:始终对 lists/arrays/groups!
的 [元素] 使用key
属性
'About me' 缺失列问题:
观察#2:
- 在(第一次渲染时)和 [图像] 加载期间 html/DOM 结构正常;
React 更新(重新渲染)中断 child div [of AboutContainer
] - 没有使用 key
(然后 VDOM 中的多个 div 没有唯一标识符) , 结果 - 更新破坏了内容结构。
但这不是唯一的原因 - 真正的原因是使用基于 <Img/>
的组件 - 对于新的 gatsby 图像插件[版本]来说已经过时了。
解决方案 #2:
您应该使用 <GatsbyImage/>
个组件。
始终确保您引用的文档是最新的!
graphql
和使用 gatsby-plugin-image
中的 GatsbyImage
/ StaticImage
组件而不是 [=15 中的 Img
组件,语法发生了重大变化=].
要修复 Portfolio.js
- 图像渲染影响了按钮链接 - 必须重构代码以适应当前引用 gatsby-plugin-image
中的 GatsbyImage
组件的语法。 graphql
和 useStaticQuery
语法也必须重构。如需更多信息,请访问 Gatsby's documentation (thanks to @xadm 为我指明正确的方向)。
About.js
也通过更新语法修复了...除了这个 Img
标记更改为 StaticImage
并且 graphql
和 useStaticQuery
被完全删除.