Skip to content

[2020-03-29]react-weather-app專案紀錄 #48

@pdji1602003

Description

@pdji1602003

學習紀錄:

  1. 在基於React庫的專案中,我們不會直接跟DOM打交道,而是跟React庫所具有的虛擬DOM進行交互。那麼直接透過useEffect去針對html元素進行修改是good practice嗎?
useEffect(() => {
    if(isSidebarOpen){
      document.body.classList.add('hideScrollbar')
    }
    return () => {
      document.body.classList.remove('hideScrollbar')
    }
  }, [isSidebarOpen])

於2020/03/30更新:
關於以上問題,基於在Discord上詢問的結果,我目前的理解是,的確直接以document取得元素並進而去進行修改是不建議的(會mutate the dom; it's therefore not advisable)。

但是在我所給出的例子中,因為body元素超出react所能handle的範圍,所以可以這樣做。

  1. useEffect裡cleanup function的使用情境以及時機?
  2. 使用axios拿取資料後,使用.catch不就可以進行錯誤處理了,為何還要進行以下response.status === 200的確認?
function handleReponse(response) {
  if (response.status === 200) {
    return response
  } else {
    throw new Error('Error: Location ' + response.statusText)
  }
}
  1. 透過API取為資料後,因為我們只需要一部份得資料,所以可以自建另一個function來mapping我們所需要的資料,同時去除我們不需要使用到的資料。
  2. 專案中所使用的Weather Icons,其官網上所說明的使用方式並沒有提到可以透過CDN使用,為何實際上卻可透過CDN引用,難道所有放在GitHub的repo實際上都可以透過CDN引用嗎?
  3. 可以透過import語法將JSON檔案引讓JS檔案做使用,示例如下:
import * as weatherIcons from '../icons'
  1. 從OpenWeatherMap傳回來的data中,每筆天氣會帶有icon對應的id碼(Example),可以跟Weather Icons裡的相互搭配使用。網路上已有前輩整理好各icon的id對應到Weather Icons裡class的名稱了,請見以下網址:_usage.md。它實際上就是在說在返回data中啊,weather[0].id就等同於icons.json檔案裡的數字,而這數字(就拿下面的300來說好了)會對應Weather Icons裡sprinkle的icon,所以引用的辦法就是,以返回data的icon_id去取icons.json的icon的值("sprinkle"),取到的值加上"wi-"就會等同於Weather Icons裡的class名稱,就可以順利使用Weather Icons裡的Icons了!
weather": [
{
     "id": 300,
     "main": "Drizzle",
     "description": "light intensity drizzle",
     "icon": "09d"
   }
],

*以上程式碼取自這裡

 "300": {
    "label": "light intensity drizzle",
    "icon": "sprinkle"
  },

*以上程式碼取自這裡
8. React component一定要返回something,如果針對return的東西設立條件(if(true))但沒有寫明不符條件時該怎麼處理,則React會報錯。
9. useRef的使用案例之我們想要知道某事件的發生是否在特定react component之外
範例解說:

  1. 我們使用useRef去保存我們欲被點擊的元素,在該元素上以ref此屬性就可以指定我們綁定的元素為何。
  2. 使用useRef所保存的值在react每次render中都會保持不變
  3. 之後,當事件發生時,我們檢查ref.current是否存在,若存在的話檢查ref是否存在任何子元素(包含本身元素)為event.target,若是的話,代表我們依舊點擊在元素內,而非元素外。
  4. 我突然發覺,我缺少一個重要認知,component之所以會是一個component,就是因為他們之間具有parent-child的關係。就比如說一個button component,那他的組成會是什麼?會是button element跟textNode,一個列表component,他的組成會是什麼?會是order list跟他的list Item,跟以降的所有其他child elements。所以,當今天我想要檢查我的事件是否發生在某個component之外時,我應該具備一個認知說,我要檢查此component所有組成的parent & child element是否包含這個事件,這也是為何在範例程式碼中會使用contains method的原因。
import React, { useRef, useEffect } from "react";

/**
 * Hook that alerts clicks outside of the passed ref
 */
function useOutsideAlerter(ref) {
  useEffect(() => {
    /**
     * Alert if clicked on outside of element
     */
    function handleClickOutside(event) {
      if (ref.current && !ref.current.contains(event.target)) {
        alert("You clicked outside of me!");
      }
    }

    // Bind the event listener
    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      // Unbind the event listener on clean up
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [ref]);
}

/**
 * Component that alerts if you click outside of it
 */
export default function OutsideAlerter(props) {
  const wrapperRef = useRef(null);
  useOutsideAlerter(wrapperRef);

  return <div ref={wrapperRef}>{props.children}</div>;
}

*以上程式碼取自此StackOverflow的回答
10 .<a rel="noopener noreferrer”>屬性:為了解決跨域的安全問題,當使用target="_blank"打開一個新的標籤頁時,新頁面的window物件有一個屬性opener,其指向前一個頁面的window物件,換句話說,後一個新開的頁面會獲得對前一個頁面的控制權,如此可能會產生安全性方面的問題。為了解決問題,我們就需要使用在a tag上使用rel="noopener noreferrer”聲明我們不要opener!
11. csstransition的問題:在此專案上遇到一個transition使用上的問題。是這樣的,transition指定元素屬性在過度時的效果以及花費時間,而在此專案中,我在sidebar上使用了transition效果,指定sidebar從畫面滑進跟滑出時的效果以及所花費的時間。那照理來說,此滑進滑出所使用到的屬性僅是transform: translateX(400px)而已,所以在transition屬性上有特別指定transform為其屬性值,而非all。但問題來了,在sidebar從畫面滑進時,transition有發揮作用,可在sidebar滑出時,transition就失效了(所謂的失效指的是sidebar並非慢慢滑出,而是啪一下地從螢幕上消失),後來我是將all作為transition的屬性值才成功解決這問題。為什麼呢???

.sidebar {
	position: absolute;
	z-index: 99;
	right: 0;
	display: flex;
	flex-direction: column;
	height: 100%;
	width: 400px;
	padding: 1.5rem;

	font-family: Montserrat;
	line-height: 1.5;

	background-color: white;
	box-shadow: 0px 8px 10px -5px rgba(0,0,0,0.2), 0px 16px 24px 2px rgba(0,0,0,0.14), 0px 6px 30px 5px rgba(0,0,0,0.12);
	transform: translateX(400px);
	transition: all 600ms cubic-bezier(0, 0, 0.2, 1) 0ms;
}

.sidebar.open{
	transform: translateX(0px);
}

於2020/03/31更新:
我自己透過在元素上增加/移除class測試在此過程中transition的效果是否都有成功,答案是肯定的,請見此codepen
然而,在此react專案卻並非如此,從此可推斷可能跟react有關係。根據此則回答,可能跟element上有設置position屬性,從而導致react在rerender時,transition無法成功發揮作用有關。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions