iT邦幫忙

2021 iThome 鐵人賽

DAY 13
0

Redux 官網

在還沒有加入Redux之前,資料在APP中各個view的傳遞會需要翻山越嶺,經過一個庄再到一庄:

有了 Redux 後,所有的資料就會在最上層直接存取,就會像這樣直接升級!:

鼠給!這麼厲害怎麼能不用

如此一來直接收斂資料流可以避免掉資料四散的問題,也可以讓資料流更好整理。

畫面與資料的關係

在改變參數的過程中,我們會在 view 發出一個 action ,這個 action 會在 Reducer 中,看對應到哪一個動作,就去執行你要做的 function,再來改變 store 中的值顯示在畫面中。

什麼是 store

放資料的地方,可以當作資料的集散地,在Redux中只會有一個 Store(Single source is turth)。

Create Store

./src/app/store/ 中建立一個 configureStore.js 加入下面的內容

import { configureStore } from '@reduxjs/toolkit'

export default configureStore({
  reducer: {} // 這邊我們會引入 redcuer 稍後會提到
})

加入 Provider 導入 store

在 app.js 中加入:

import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import store from './app/store/confiureStore';
import { Provider } from 'react-redux'

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

如何存取 Store 的值

我們主要有兩種方式來直接存取 store 的值。

  1. HOC => 使用 connect
  2. Hook => 使用 useSelector

使用 Container

在頁面中,我們可以透過 Container、一個最外層的容器,來連結 view :

import { connect } from 'react-redux';

import Home from './view';

const mapStateToProps = ({ auth }) => ({
    username: auth.username
});

const mapDispatchToProps = (dispatch) => ({
  // 
});

export default connect(mapStateToProps, mapDispatchToProps)(Home);

如此一來 Home 就可以透過 props 來存取到 username 這個值

import React from 'react';
import { Text } from 'react-native';

const Home = ({ username }) => {
  return <Text>{username}</Text> 
}

export default Home;

使用 Hook

使用 Hook 就不用從外部的 props 傳遞資料進來,直接在 view 中就可以存取。

import React from 'react';
import { Text } from 'react-native';
import { useSelector } from 'react-redux';

const Home = () => {  
  const username = useSelector(({ auth }) => auth.username);

  return <Text>{username}</Text> 
}

export default Home;

如何改變 Store 中的值

改變的過程比較複雜,首先我們要發出一個 action,發出的 action 經過 dispatch 來到 Reducer 中,再依照 actionType,來看要做什麼事情。

什麼是 action

action 是一個 pure function ,舉例來說,我要進行一個 改變 username 的動作 ,那我的 action 可以這樣寫:

const editUsernameAction = (payload) => ({
   type: 'EDIT_USERNAME', // actionType 用來識別進入 Reducer 要做什麼事
   payload //帶入的參數
})

發出一個 action 一樣的兩種方式:

  1. HOC => 使用 connect
  2. Hook => 使用 useDispatch

使用 HOC

mapDispatchToProps 中,加入我們上面提到的 editUsernameAction

import { connect } from 'react-redux';
import { editUsernameAction } from '~/actions/userActions'
import Home from './view';

const mapStateToProps = ({ auth }) => ({
    username: auth.username
});

const mapDispatchToProps = (dispatch) => ({
  handleUpdateUsernem: payload => {
     dispatch(editUsernameAction(payload));
  } 
});

export default connect(mapStateToProps, mapDispatchToProps)(Home);

如此一來就可以在 Home 中用 props 找到 handleUpdateUsernem
以下是在 input 中輸入 username,按下送出來更新 username:

import React, {useState} from 'react';
import { Text, TextInput, View, Button } from 'react-native';

const Home = ({ username, handleUpdateUsernem }) => {
  const [ payload, setPayload ] = useState('');

  return (
    <View>
        <Text>{username}</Text> 
        <TextInput value={payload} onChange={value => setPayload(value)}/>
        <Button title="送出" onPress={ () => handleUpdateUsernem(payload)}/>
    </View>
  )
  
}

export default Home;

使用 Hook

使用 Hook 就是把 dispatch 這段拿到 view 中:

import React, {useState} from 'react';
import { useSelector } from 'react-redux';
import { Text, TextInput, View, Button } from 'react-native';
import { editUsernameAction } from '~/actions/userActions'

const Home = ({ username, handleUpdateUsernem }) => {
  const [ payload, setPayload ] = useState('');
  
  const username = useSelector(({ auth }) => auth.username);
  const dispatch = useDispatch(); // 這邊拿到 dispatch
  
  const handleUpdateUsernem = () => {
     dispatch(editUsernameAction(payload)); // 這邊去呼叫他
  }

  return (
    <View>
        <Text>{username}</Text> 
        <TextInput value={payload} onChange={value => setPayload(value)}/>
        <Button title="送出" onPress={handleUpdateUsernem}/>
    </View>
  )
  
}

export default Home;

發出了一個 action 然後呢? 進到 Reducer

我們在 ./src/reducers/ 中建立一個 userReducer.js

export default function reducer(user = userState, { type, payload }) {
  switch (type) {
  case 'EDIT_USERNAME':
      return { ...user, username: payload };
  default:
      return user;          
  }
}

./src/reducers/ 中建立一個 index.js。接著我們要將所有的 reducer 疊加再一起,這時候我們會用到 combineReducers :

import user from './userReducer';

export default combineReducers({
  user
});

最後將 Reducer 連結回 Store

import { configureStore } from '@reduxjs/toolkit'
import reducer from '~/src/reducer';

export default configureStore({
  reducer // 這邊我們會引入上方的 combine 後的 reducer
})

這樣我們的一個資料循環就完成了:


上一篇
[Day12 - React Native] 為你的 APP 加入 icon - Android
下一篇
[Day14] React Native - Redux Saga
系列文
30 天程式邊緣人 - React Native 的孤獨開發指南15
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言