[Day13] React Native - 整理资料流,使用 Redux 吧!

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
})

这样我们的一个资料循环就完成了:


<<:  Laravel 的 MVC 与 Router

>>:  Day 28 | SQLite资料库(三)

Day 29 - BFS

大家好,我是长风青云。今天是铁人赛的29天。这是我最後一个要讲的演算法喔。 如果明天的部分不想看不想...

Day 13 运算宝石:【Lab】EC2储存资源 EBS Volume 建立与使用 (下)

今天,我们继续【Lab】EC2储存资源 EBS Volume 建立与使用下半部分。 连进 EC2 ...

【领域展开 01 式】 术式修炼前的理性条列思考

Hi 铁人赛,这是第二次参加 2021 年又再次参与 IT 铁人赛,去年参加是因为觉得 30 岁前要...

Day23 - 静态模型 part1 (MLP)

完整的语音情绪辨识系统流程如图 1。语音讯号先经过特徵撷取的过程撷取出声学特徵,再将声学特徵进行前处...

【在 iOS 开发路上的大小事-Day07】除了用 WKWebView 以外,还可以如何在 App 中显示 PDF 档案呢?

前情提要 一般我们要在 App 中显示 PDF 档案,可能会透过 WKWebView 来进行实作 最...