用React刻自己的投资Dashboard Day8 - useState hook

tags: 2021铁人赛 React

在Card元件中有使用到useState,是React中一个蛮重要的hook,是一个非常强大的功能,看起来跟用起来都非常的简洁,这篇就来分析一下useState的用法及背後的原理。

Hook是什麽

引用自React官网

Hook 是 React 16.8 中增加的新功能。它让你不必写 class 就能使用 state 以及其他 React 的功能。

然後很棒的一点是向下相容class,react官网也有说明三点如下:

  • 完全自由选择使用。你可以在几个 component 中试用 Hook 而不用重写任何既有的程序码。不过如果你不想要,并不需要现在学习或使用 Hook。
  • 100% 向下相容。Hook 没有任何 breaking change。
  • 目前没有计画要从 React 移除 class。

useState hook范例

这边就写个范例来认识hook跟class在使用上有什麽不同:

  • 程序码比较图
    这个范例是点击按钮之後,点击次数会加1,是个相当简单的例子。程序码比较如下图,左边是class版本,右边是hook版本。可以发现class版本的程序码稍微比较长一些,不过这个范例只有定义一个state,如果同时有很多个state需要管理的时候,那程序码的数量就会差很多。另外就是一个是用class component,一个是用function component,这个要比较的话又可以再写一篇文章,这边就先省略。

    如果想要实际测试的朋友,这边提供两个codepen可以参考:
    * class版本:https://codepen.io/siang720/pen/VwbOzby
    * hook版本:https://codepen.io/siang720/pen/eYWaGwj

  • useState使用方式

    • 宣告state的方式如下程序码,useState会回传一个array,里面有两个element,下面这行的意思就是让count与setCount去对应回传的两个element,而state的初始值是0。count就是要管理的state,setCount则是用来做状态管理的函数,这两个变数是可以任意命名的。
    const [count, setCount] = useState(0);
    
    • 变更state的方式:如范例中的程序码,呼叫setCount,并将调整state的方式放在括号内,这个例子里面调整count这个state的方式就是让它等於原本的值再加上1。
    const buttonClickHandler = () => {
        setCount(count + 1)
    };
    
    • 重新渲染:一旦state的状态被改变之後,react就会重新渲染有改变的element。

state也可以是一个物件

上述的范例的state是一个number,不过其实state还可以是object,如同Day6里面的Card.js,里面所管理的state就是一个物件。我将highchart要用到的option写成一个state来管理,因为option里面要引入数据,而数据需要call api取得,因此我希望call完api之後,将得到的数据放入state,让react可以知道有东西更新了,就会去重新渲染图表。

Card.js

const Card = (props) => {
  // 定义state
  const [chartOption, setChartOption] = useState({
    title: {
      text: props.item.title
    },
    xAxis: {
      type: "datetime",
      title: {
        text: 'Date'
      }
    }
  });

  // 抓取资料
  const fetchData = (series_id) => {
    fetch(`${process.env.REACT_APP_PROXY_SERVER_URL}/series/observations?series_id=${series_id}&api_key=${process.env.REACT_APP_API_KEY}&file_type=json`, {
      headers: {
        'Target-URL': 'https://api.stlouisfed.org/fred'
      }
    })
      .then((response) => response.json())
      .then((data) => {
        let data1 = [];
        data.observations.forEach(ob => {
          data1.push([new Date(ob.date).getTime(), Number(ob.value)]);
        });
        
        // 将数据导入option state
        setChartOption((prevOption) => {
          return {
            ...prevOption,
            series: [
              {
                name: props.item.title,
                data: data1
              }
            ]
          }
        })
      });
  };
  
  // 另外一个hook,下一篇说明,功能是用来让网页一载入即call api抓资料
  useEffect(() => {
    fetchData(props.item.series_id);
  }, []);

  return (
    <div className={styles.chartFrame}>
      <HighchartsReact
        highcharts={Highcharts}
        constructorType={'stockChart'}
        options={chartOption}
      />
      <div className={styles.chartInfo}>
        <p className={styles.source}>source: {props.item.source}</p>
        <p className={styles.date}>updated: {props.item.updated}</p>
      </div>
      <div>
        <p className={styles.document}>{props.item.document}</p>
      </div>
    </div>
  )
}

export default Card;

上面程序码宣告state的部分撷取如下:

  // 定义state
  const [chartOption, setChartOption] = useState({
    title: {
      text: props.item.title
    },
    xAxis: {
      type: "datetime",
      title: {
        text: 'Date'
      }
    }
  })

这个state为了符合highchart套件的格式,所以看起来稍微复杂了一些。

将数据导入state的程序码撷取如下:
prevOption指得是既有的state状态,这边做的是不变更既有的状态,在option内加series。

setChartOption((prevOption) => {
  return {
    ...prevOption,
    series: [
      {
        name: props.item.title,
        data: data1
      }
    ]
  }
})

所以经由setChertOption修改後,chartOption应该会是下面这样:

{
    title: {
      text: props.item.title
    },
    xAxis: {
      type: "datetime",
      title: {
        text: 'Date'
      }
    },
    series: [
      {
        name: props.item.title,
        data: data1
      }
    ]
 }

小结

useState看起来非常的简洁,真的是一个很棒的hook,下一篇就来介绍一下这篇还没讲到的useEffect hook,它可以解释为什麽进入网页後,react会自动去抓取资料并且呈现在图表上。


<<:  使用回归分析与其意义 | ML#Day15

>>:  [DAY9]观察heroku logs

【Day 14】 实作 - 透过 AWS 服务 - QuickSight 建立互动式仪表板 ( 2 )

大家早安 最近一直活在赶文章的生活中,终於完成快 50 % 的进度,感动想哭 前几天我们顺利撷取 G...

Now available the of Spotify Premium APK for all Android

Although YouTube Music hit the global market a few...

[Day19] swift & kotlin 游戏篇!(1) 小鸡BB-游戏制作-按钮排版

游戏説明 接下来我们要来制作真正的游戏了 游戏就是猜 左右两只小鸡谁先破蛋 然後落入蓝色还是红色蓝子...

Day 03 - 行前说明 — 在 MVC & MVVM 的 UI 元件

相信网路上其实已经有不少文章在谈架构了,我的资历也尚浅,今天虽然会介绍架构,但是主要会侧重的点会是...

[ JS个人笔记 ] 传值传址&深浅层拷贝—DAY5

传值(call by value)vs传址(call by reference) 基本型别(Numb...