【React Native + Expo】useContextとuseReducerの利用方法について②
Qiita初心者です。
誤字脱字、至らない点があるかもしれませんがよろしくお願いします。
以前上記で質問をさせていただきましたが、追加で不明点が出てきました。
解決したいこと
React Native + Expoでスマホアプリをつくっています。
hooksのuseContextとuseReducerを使用し
グローバルな値をどのコンポーネントでも更新、取得ができるようにしたいです。
以下キャプチャの画面より、左右の矢印を押して日付を変更すると、
日付表示が変わり、その日に飲んだミルクの合計量を表示させたいです。
DBはFireBaseを使用しており、データ構造は以下となります
わからないこと
日付変更は既にhooksを使用しデータの更新や取得ができていますが、
DB上にある配列データの取得と更新方法がわかりません
【不明点①】
初期値の設定方法(当日のミルク合計値を設定)
※TestContext.jsxのconst dataまではデータが取得できていることをログで確認していますが、そこからstateへの設定方法がわかりません
【不明点②】
日付を変更した際に、変更後の日付でミルクの合計値を再取得し表示
React Nativeも初心者なもので、
解決策についてご教示いただけましたら幸いです。
また、以下記事を参考にさせていただきました。
該当のコード
【親コンポーネント】
TestScreen.jsx
import React from 'react';
import { View } from 'react-native';
import TestComponent from '../components/TestComponent';
import { CountProvider } from '../context/TestContext';
export default function TestScreen() {
return (
<CountProvider>
<View>
< TestComponent />
</View>
</CountProvider>
);
}
【子コンポーネント】
TestComponent.jsx
import React from 'react';
import firebase from 'firebase';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { useTestContext } from '../context/TestContext';
export default function TestComponent() {
const { state, dispatch } = useTestContext();
const dayOfWeek = [ "日", "月", "火", "水", "木", "金", "土" ] ;
return (
<View>
<View style={styles.date}>
<TouchableOpacity
onPress={ () => dispatch({
type: "decrement",
year: state.year,
month: state.month,
day: state.day,
youbiCount: state.youbiCount
})} style={styles.dateText}>
<Text style={styles.cursorText}>◀︎</Text>
</TouchableOpacity>
<Text style={styles.dateText}>
{state.year}年{state.month}月{state.day}日({dayOfWeek[state.youbiCount]})
</Text>
<TouchableOpacity
onPress={ () => dispatch({
type: "increment",
year: state.year,
month: state.month,
day: state.day,
youbiCount: state.youbiCount
})} style={styles.dateText}>
<Text style={styles.cursorText}>▶︎</Text>
</TouchableOpacity>
</View>
<View style={styles.date}>
<Text>飲んだmilkの合計量 → "○○"ml</Text>
</View>
</View>
)
};
const styles = StyleSheet.create({
date: {
flexDirection: 'row',
height: 70,
alignItems:'center',
justifyContent: 'center',
},
dateText: {
fontSize: 20,
paddingHorizontal: 10,
},
cursorText: {
fontSize: 40,
},
});
【Contextファイル】
TestContext.jsx
import React, { createContext, useReducer, useContext} from 'react';
import firebase from 'firebase';
//========
// Context
//========
const TestContext = createContext();
export function useTestContext() {
return useContext(TestContext);
}
export function CountProvider({ children }) {
//========
// 初期値設定
//========
const date = new Date(Math.floor(new Date().getTime()/1000/60/5)*1000*60*5);
const db =firebase.firestore();
const { currentUser } = firebase.auth();
const initialState = {
year: Number(date.getFullYear()),
month: Number(date.getMonth() + 1),
day: Number(date.getDate()),
hours: Number(date.getHours()),
minutes: Number(date.getMinutes()),
youbiCount: Number(date.getDay()),
};
//ここからわからない=====================
//========
// DB接続、値取得
//========
let unsubscribe = () => {};
if (currentUser) {
const ref = db.collection(`users/${currentUser.uid}/${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`).orderBy('updatedAt', 'asc');
unsubscribe = ref.onSnapshot((snapshot) => {
snapshot.forEach((doc) => {
const data = doc.data();
});
}, (error) => {
console.log(error);
Alert.alert('データの読み込みに失敗しました。');
});
}
//=====================ここまでわからない
const reducer = (state, action) => {
let endDate = new Date(action.year, action.month, 0) // 月の最後の日を取得
let endDayCount = endDate.getDate() // 月の末日
//========
// 日付変更処理
//========
if (action.type == "increment") {
if (action.day != null) {
state.day = action.day + 1;
state.youbiCount = action.youbiCount + 1;
//末日の場合は翌月の1日に設定する
if (state.day > endDayCount) {
state.day = 1;
if (action.month < 12) {
state.month = action.month + 1;
} else if (action.month = 12){
state.month = 1;
state.year = action.year + 1;
}
};
//土曜日の場合は日曜日に設定
if (state.youbiCount >= 7) {
state.youbiCount = 0;
}
};
} else if (action.type == "decrement") {
if (action.day != null) {
state.day = action.day - 1;
state.youbiCount = action.youbiCount - 1;
// 前の月の場合は前月の末尾を取得する
if (state.day < 1) {
endDate = new Date(action.year, action.month-1, 0) // 前月の最後の日を取得
endDayCount = endDate.getDate() // 前月の末日
state.day = endDayCount;
if (action.month > 1) {
state.month = action.month - 1;
} else if (action.month = 1){
state.month = 12;
state.year = action.year - 1;
}
}
//日曜日の場合は土曜日に戻る
if (state.youbiCount <= -1) {
state.youbiCount = 6;
}
};
};
//========
// 時間変更処理
//========
if (action.type == "timeUpdate") {
if (action.hours != null && action.minutes != null ) {
state.hours = action.hours;
state.minutes = action.minutes;
};
};
return {
year: state.year,
month: state.month,
day: state.day,
hours: state.hours,
minutes: state.minutes,
youbiCount: state.youbiCount,
memos: state.memos,
unsubscribe,
};
};
const [state, dispatch] = useReducer(reducer, initialState);
return (
<TestContext.Provider value={{state, dispatch}}>
{children}
</TestContext.Provider>
);
}
よろしくお願いいたします。
0