How to toggle an on/off switch with redux toolkit? - reactjs

I`m trying to implement a switch that can be switched on and off and according to the state a different image and text is shown. With the help of a tutorial I did the following:
First I created store.js:
import { configureStore } from '#reduxjs/toolkit';
import switchReducer from './switch';
export const store = configureStore({
reducer: {
switchVal: switchReducer
}
});
Then I created switch.js
import { createSlice } from '#reduxjs/toolkit';
const switchSlice = createSlice({
name: 'alarm',
initialState: {
active: true
},
reducers: {
toggleSwitch: (state) => {
state.active = !state.active;
},
}
});
export const toggleSwitch = switchSlice.actions.toggleSwitch;
export default switchSlice.reducer;
In App.js I imported {store} and wrapped around my BottomTab Navigator.
Now the switch is in Alarm.js which looks like this:
import React from 'react';
import { StyleSheet, Text, View, Image, ScrollView, Pressable, Switch } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import { globalStyles } from '../components/globalStyles';
import { toggleSwitch } from '../components/switch';
function Alarm({navigation}) {
const switchValue = useSelector((state) => state.switchValue);
const dispatch = useDispatch();
const alarmEnabled = require('../images/Alarm_enabled.png');
const alarmDisabled = require('../images/Alarm_disabled.png');
function toggleSwitchHandler() {
if (switchValue == true) {
dispatch(toggleSwitch(value));
} else {
dispatch(toggleSwitch(value));
}
}
return (
<ScrollView>
<View style={globalStyles.containerBodyAlarm}>
<View style={globalStyles.containerMainAlarm}>
<View style={globalStyles.containerImageAlarm}>
<Image style={{ width: 130, height: 130, resizeMode: 'contain', marginTop: 20, marginBottom: 10}} source={switchValue ? alarmDisabled : alarmEnabled } />
</View>
<View style={globalStyles.containerButtonAlarm}>
<Text style={globalStyles.textButtonAlarm}>{switchValue ? 'Alarm is deactivated' : 'Alarm is activated'}</Text>
<Switch
trackColor={{false: '#919190', true: '#000099'}}
thumbColor={'#5E5E5D'}
value={switchValue}
onValueChange= {toggleSwitchHandler}
/>
<Text style={globalStyles.textButtonAlarm2}>{switchValue ? 'activate' : 'deactivate'}</Text>
</View>
</View>
</View>
</ScrollView>
);
}
export default Alarm;
const styles = StyleSheet.create({
pressed: {
opacity: 0.7,
},
Unfortunately it's not working. What am I doing wrong? I'm sorry for the bad coding, I'm not good at it.

Your initial state looks like:
initialState: {
active: true
},
However, you are getting the value by doing:
const switchValue = useSelector((state) => state.switchValue);
That does not exist, it needs to be:
const switchValue = useSelector((state) => state.active);
function toggleSwitchHandler() {
if (switchValue == true) {
dispatch(toggleSwitch(value));
} else {
dispatch(toggleSwitch(value));
}
}
The if here has no use since both callers have the same props.
Also, value does not exist, since you're flipping the boolean inside the reducer, no need for the param.
Change it to:
function toggleSwitchHandler() {
dispatch(toggleSwitch());
}
To invert the current boolean

you can make 2 reducers, one with value true the other with value false
import { createSlice } from '#reduxjs/toolkit';
const initialStateValue = {
active: true
}
const switchSlice = createSlice({
name: 'alarm',
initialState: initialStateValue,
reducers: {
toggleOn: (state = initialStateValue) => {
state.active = true;
},
toggleOff: (state = initialStateValue) => {
state.active = false;
}
}
});
export const {toggleOn, toggleOff} = switchSlice.actions;
export default switchSlice.reducer;
get the value of toggle
const switchValue = useSelector((state) => state.alarm.active);
use it
function toggleSwitchHandler() {
if (switchValue == true) {
dispatch(toggleOff());
} else {
dispatch(toggleOn());
}
}

setLogin: (state, action) => {
const toggle = (input) => !input;
state.active = toggle(state.active);
},
I was having the same issue and came up with above solution. :)

Related

How can I change my data fetching strategy to avoid stale data on initial dynamic route renders?

I'm building a Next.js app which allows users to create and view multiple Kanban boards. There are a couple of different ways that a user can view their different boards:
On the Home page of the app, users see a list of boards that they can click on.
The main navigation menu has a list of boards users can click on.
Both use Next.js Link components.
Clicking the links loads the following dynamic page: src/pages/board/[boardId].js The [boardId].js page fetches the board data using getServerSideProps(). An effect fires on route changes, which updates the redux store. Finally, the Board component uses a useSelector() hook to pull the data out of Redux and render it.
The problem I'm experiencing is that if I click back and forth between different boards, I see a brief flash of the previous board's data before the current board data loads. I am hoping someone can suggest a change I could make to my approach to alleviate this issue.
Source code:
// src/pages/board/[boardId].js
import React, { useEffect } from 'react'
import { useDispatch } from 'react-redux'
import Board from 'Components/Board/Board'
import { useRouter } from 'next/router'
import { hydrateTasks } from 'Redux/Reducers/TaskSlice'
import { unstable_getServerSession } from 'next-auth/next'
import { authOptions } from 'pages/api/auth/[...nextauth]'
import prisma from 'Utilities/PrismaClient'
const BoardPage = ({ board, tasks }) => {
const router = useRouter()
const dispatch = useDispatch()
useEffect(() => {
dispatch(hydrateTasks({ board, tasks }))
}, [router])
return (
<Board />
)
}
export async function getServerSideProps ({ query, req, res }) {
const session = await unstable_getServerSession(req, res, authOptions)
if (!session) {
return {
redirect: {
destination: '/signin',
permanent: false,
},
}
}
const { boardId } = query
const boardQuery = prisma.board.findUnique({
where: {
id: boardId
},
select: {
name: true,
description: true,
id: true,
TO_DO: true,
IN_PROGRESS: true,
DONE: true
}
})
const taskQuery = prisma.task.findMany({
where: {
board: boardId
},
select: {
id: true,
title: true,
description: true,
status: true,
board: true
}
})
try {
const [board, tasks] = await prisma.$transaction([boardQuery, taskQuery])
return { props: { board, tasks } }
} catch (error) {
console.log(error)
return { props: { board: {}, tasks: [] } }
}
}
export default BoardPage
// src/Components/Board/Board.js
import { useEffect } from 'react'
import { useStyletron } from 'baseui'
import Column from 'Components/Column/Column'
import ErrorBoundary from 'Components/ErrorBoundary/ErrorBoundary'
import useExpiringBoolean from 'Hooks/useExpiringBoolean'
import { DragDropContext } from 'react-beautiful-dnd'
import Confetti from 'react-confetti'
import { useDispatch, useSelector } from 'react-redux'
import useWindowSize from 'react-use/lib/useWindowSize'
import { moveTask } from 'Redux/Reducers/TaskSlice'
import { handleDragEnd } from './BoardUtilities'
import { StyledBoardMain } from './style'
const Board = () => {
const [css, theme] = useStyletron()
const dispatch = useDispatch()
useEffect(() => {
document.querySelector('body').style.background = theme.colors.backgroundPrimary
}, [theme])
// get data from Redux
const { boardDescription, boardName, columnOrder, columns, tasks } = useSelector(state => state?.task)
// set up a boolean and a trigger to control "done"" animation
const { boolean: showDone, useTrigger: doneUseTrigger } = useExpiringBoolean({ defaultState: false })
const doneTrigger = doneUseTrigger({ duration: 4000 })
// get width and height for confetti animation
const { width, height } = useWindowSize()
// curry the drag end handler for the drag and drop UI
const curriedDragEnd = handleDragEnd({ dispatch, action: moveTask, handleOnDone: doneTrigger })
return (
<ErrorBoundary>
<DragDropContext onDragEnd={curriedDragEnd}>
<div className={css({
marginLeft: '46px',
marginTop: '16px',
fontFamily: 'Roboto',
display: 'flex',
alignItems: 'baseline'
})}>
<h1 className={css({ fontSize: '22px', color: theme.colors.primary })}>{boardName}</h1>
{boardDescription &&
<p className={css({ marginLeft: '10px', color: theme.colors.primary })}>{boardDescription}</p>
}
</div>
<StyledBoardMain>
{columnOrder.map(columnKey => {
const column = columns[columnKey]
const tasksArray = column.taskIds.map(taskId => tasks[taskId])
return (
<Column
column={columnKey}
key={`COLUMN_${columnKey}`}
tasks={tasksArray}
title={column.title}
status={column.status}
/>
)
})}
</StyledBoardMain>
</DragDropContext>
{showDone && <Confetti
width={width}
height={height}
/>}
</ErrorBoundary>
)
}
export default Board
// src/pages/index.tsx
import React, {PropsWithChildren} from 'react'
import {useSelector} from "react-redux";
import {authOptions} from 'pages/api/auth/[...nextauth]'
import {unstable_getServerSession} from "next-auth/next"
import CreateBoardModal from 'Components/Modals/CreateBoard/CreateBoard'
import Link from 'next/link'
import {useStyletron} from "baseui";
const Index: React.FC = (props: PropsWithChildren<any>) => {
const {board: boards} = useSelector(state => state)
const [css, theme] = useStyletron()
return boards ? (
<>
<div style={{marginLeft: '46px', fontFamily: 'Roboto', width: '600px'}}>
<h1 className={css({fontSize: '22px'})}>Boards</h1>
{boards.map(({name, description, id}) => (
<Link href="/board/[boardId]" as={`/board/${id}`} key={id}>
<div className={css({
padding: '20px',
marginBottom: '20px',
borderRadius: '6px',
background: theme.colors.postItYellow,
cursor: 'pointer'
})}>
<h2 className={css({fontSize: '20px'})}>
<a className={css({color: theme.colors.primary, width: '100%', display: 'block'})}>
{name}
</a>
</h2>
<p>{description}</p>
</div>
</Link>
))}
</div>
</>
) : (
<>
<h1>Let's get started</h1>
<button>Create a board</button>
</>
)
}
export async function getServerSideProps(context) {
const session = await unstable_getServerSession(context.req, context.res, authOptions)
if (!session) {
return {
redirect: {
destination: '/signin',
permanent: false,
},
}
}
return {props: {session}}
}
export default Index
It looks like there's only ever one board in the redux. You could instead use a namespace so that you don't have to keep swapping different data in and out of the store.
type StoreSlice = {
[boardId: string]: Board;
}
Then the "brief flash" that you will see will either be the previous data for the correct board, or nothing if it has not yet been fetched.

Bug that I can't understand and fix in React Native

To put in context I am building an app as an exercise in a course to program in react native and we are learning Redux
For me everything is fine but I have doubts in two parts in the index of the scene where the application is seen in this case welcome / index.js there is a line that is for 'useSelector' and another is in the reduce of recipe that if the data is well linked because it throws me an error.
"ERROR TypeError: undefined is not an object (evaluating 'store.getState')"
I share the different components of the redux.
Everything is in a store folder and everything is modulated
store/reduce
store/reduce/index.js
import { combineReducers, createStore } from "redux";
import { recipesReducer } from "./reducer";
const rootReducer = combineReducers({
recipes: recipesReducer
});
export default createStore(rootReducer);
store/reducer/recipes.reducer.js
import {recipeTypes} from '../types';
import {recipes} from '../../data';
const { SELECT_RECIPE } = recipeTypes;
const initialState = {
recipes: recipes,
selectedRecipe: null
}
const recipesReducer = (state = initialState, action) => {
switch(action.type) {
case SELECT_RECIPE:
const indexRecipe = state.recipes.findIndex(
(recipe) => recipe.id === action.recipeId
);
if(indexRecipe === -1) return state;
return {
...state,
selectedRecipe: state.recipes[indexRecipe]
}
default:
return state;
}
}
export default recipesReducer;
store/reduce/index.js
export {default as recipesReducer} from './recipes.reducer';
store/types/index.js
export * from './recipes.types';
store/types/recipes.type.js
export const recipeTypes = {
SELECT_RECIPE: 'SELECT_RECIPE',
}
store/action/recipes.action.js
import { recipeTypes } from '../types';
const { SELECT_RECIPE } = recipeTypes;
export const selectRecipe = (id) => {
return {
type: SELECT_RECIPE,
recipeId: id,
};
}
store/action/index.js
export * from './repice.action';
welcome/index
import {Button, CardsRecipes, MenuAlt, Pickers, TT} from '../../components';
import { FlatList, StyleSheet, Text, View } from 'react-native';
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import Color from '../../constants/colors';
import { recipe } from '../../data';
import { selectRecipe } from '../../store/action';
const Welcome= ({navigation, route}) => {
const dispatch = useDispatch();
const recipe = useSelector(state => state.recipe.recipe);
const onSelected = (item) => {
dispatch(selectRecipe(item.id));
navigation.navigate('Recipe');
}
const renderItem = ({item}) => <CardsRecipes item={item} onSelected={onSelected(item)} />
return (
<View style={styles.container}>
<MenuAlt title = {'Recetas'} />
<View style={styles.textContainer}>
<Text style= {styles.text}>Bienvenido a la App de Recetas de Cocina</Text>
</View>
<View style = {styles.buttonContainer}>
</View>
<FlatList
data= {recipe}
renderItem = {renderItem}
keyExtractor = {item => item.id}
/>
</View >
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: Color.primary,
color: Color.letter,
fontFamily: 'Lato-Regular',
},
textContainer: {
alignItems: 'center',
justifyContent: 'center',
},
text: {
color: Color.letter,
fontSize: 20,
fontWeight: 'bold',
marginTop: 10,
marginBottom: 10,
},
buttonContainer: {
width: '100%',
alignItems: 'center',
marginTop: 10,
marginBottom: 10,
height: 33,
},
});
export default Welcome;
app.js
import {ActivityIndicator, StyleSheet, View} from 'react-native';
import React, { useState } from 'react';
import AppNavigator from './navigation';
import Color from './constants/colors';
import { Provider } from 'react-redux';
import { StatusBar } from 'expo-status-bar';
import { store } from './store';
import { useFonts } from 'expo-font';
export default function App() {
//useState
const [selected, setSelected] = useState(false);
const [order, setOrder] = useState([]);
//funciones
const [loaded] = useFonts({
'Lato-Regular': require('./assets/fonts/Lato-Regular.ttf'),
'Lato-Bold': require('./assets/fonts/Lato-Bold.ttf'),
'Lato-Light': require('./assets/fonts/Lato-Light.ttf'),
'Lato-Italic': require('./assets/fonts/Lato-Italic.ttf'),
'Lato-Black': require('./assets/fonts/Lato-Black.ttf'),
});
if(!loaded) {
return (
<View style={styles.containerLoader}>
<ActivityIndicator size="large" color={Color.letter} />
</View>
)
}
const onSelectedEnlarge = ( select, order ) => {
setOrder(order)
setSelected(select);
};
/*
let content = <Super onSelectedEnlarge={onSelectedEnlarge} object = {order}/>;
if (!selected) {
content = <Super onSelectedEnlarge={onSelectedEnlarge} object = {order}/>;
}
else
{
content = <ListSuper onSelectedEnlarge={onSelectedEnlarge} object = {order}/>;
}
*/
return (
<Provider store={store}>
<AppNavigator/>
</Provider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: Color.primary,
color: Color.letter,
fontFamily: 'Lato-Regular',
},
});
thanks for your help

how can I send props to other file?

How can I send props to another file?
I have a component file. And there is an array where data are pushed. If the user click ok, then I want the array to another file.
example:
sizeComponent.js
import React from 'react';
import { StyleSheet, View, Text, TouchableOpacity, FlatList, Dimensions } from 'react-native';
import pure from 'recompose/pure';
const width = Dimensions.get('window').width;
const height = Dimensions.get('window').height;
const AboveSize = ({ data, onPress }) => {
return (
<View style={{marginTop: 10}}>
<Text style={{color: '#333', fontSize: 16}}>Bekleidungsgröße</Text>
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
<FlatList
data={data}
keyExtractor={item => item.key}
horizontal
getItemLayout={(data, index) => {
return {
index,
length: 200,
offset: height * index
}
}}
showsHorizontalScrollIndicator={false}
renderItem={({ item }) => {
return (
<TouchableOpacity onPress={onPress} style={{borderWidth: 1, borderColor: '#ccc', justifyContent: 'center', alignItems: 'center', borderRadius: 8, height: 77, width: 77, margin: 12, marginLeft: 0, backgroundColor: data.includes(item.size) ? 'red' : 'blue'}}>
<Text style={{color: data.includes(item.size) ? '#fff' : '#333', fontSize: 20}}>{item.size}</Text>
</TouchableOpacity>
)
}}
/>
</View>
</View>
)
};
export default pure(AboveSize);
Main.js
import SizeComponent from 'sizeComponent';
/* Size from Mock Data */
const productData = [
{
item: {
id: 1,
name:"Calvin Klein Bag",
price:"29.99€",
size: [
{
key: "1",
size: "XS"
},
{
key: "2",
size: "S",
},
{
key: "3",
size: "M"
},
{
key: "4",
size: "L"
},
{
key: "5",
size: "XL"
},
{
key: "6",
size: "XXL"
},
{
key: "7",
size: "XXXL"
}
],
}
}];
const [productSize, setProductSize] = useState([]);
...
<SizeComponent data={productData} onPress={() => console.log('I want here the data from the component file which was selected')}
In the sizeComponent.js change the onPress method to the following code:
<TouchableOpacity onPress={()=>onPress(item)}
so when the onPress is called the selected item will be passed to the callback method which you can access like this
<SizeComponent data={productData} onPress={(item) => {//the seleteced item will be accessible here })
React Native applications are built using components that manage state internally.
To globalize your state there is a state management libraries like Redux exist to solve this issue. Redux provides a central location for all the states of an application where each component can access the values stored in the state.
reducer.js
import { combineReducers } from "redux";
const INITIAL_STATE = { table:[] };
const reducers = (state = INITIAL_STATE, action) => {
switch (action.type) {
case "PUSH_TABLE":
state.table.push(action.value)
return { ...state, table: state.table };
default:
return state;
}
};
export default combineReducers({ reducers: reducers });
action.js
export const pushTable = (title) => ({
type: "PUSH_TABLE",
value: title
});
app.js
import React from "react";
import ListScreen from "./src/ListScreen";
import ModalScreen from "./src/ModalScreen";
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import { Provider } from "react-redux";
import { createStore } from "redux";
import reducer from "./src/reducer";
const store = createStore(reducer);
const Stack = createStackNavigator();
function MainStackNavigator() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="List" component={ListScreen} />
<Stack.Screen name="Modal" component={ModalScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default function App() {
return (
<>
<Provider store={store}>
<MainStackNavigator />
</Provider>
</>
);
}
Table.js
import React from "react";
import { Button } from "react-native";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import { pushTable } from "./action";
class Table extends React.Component {
render() {
return (
<>
<Button
title={"PUSH TABLE"}
onPress={() => this.props.pushTable("NICE") }
/>
{this.props.reducers.table.map((cel, index) => (
<Text>{cel} {index}</Text>
))}
</>
);
}
}
const mdtp = (dispatch) => bindActionCreators( { pushTable, }, dispatch );
const mtp = (state) => {
const { reducers } = state;
return { reducers };
};
export default connect(mtp, mdtp)(Table);

Redux with React Native state not updating

I tried to add a recipe to favourites using Redux with React Native.
If I use the state in the favicon.js this works fine but does not work with Redux.
This is my favicon.js
import React, {useState} from 'react'
import { FontAwesome } from '#expo/vector-icons'
import { View, TouchableOpacity,StyleSheet, Text, Alert } from 'react-native'
import { connect } from 'react-redux'
import { toggleFavId, isFavourite } from '../actions'
const FavIcon = ({recipeid, toggle, isFav, text}) => {
// const [isFavNew, setFavNew] = useState(false)
// const toggleFav = (recipeid) =>{
// setFavNew(!isFavNew)
// console.log(`Entered toggle ${recipeid} isfavnew = ${isFavNew}`)
// }
return (
<View>
<TouchableOpacity style={styles.favItem} onPress={() => {toggle(recipeid)}}>
<FontAwesome name={isFav == true ? 'heart' : 'heart-o'} size={40} color='red' />
<Text> {text}</Text>
</TouchableOpacity>
</View>
)
}
const mapStateToProps = (state) =>({
favids: state.favids,
})
const mapDispatchToProps = (dispatch) => ({
toggle: (recipeid) => dispatch(toggleFavId(recipeid)),
isFav: (recipeid) => dispatch(isFavourite(recipeid)),
})
export default connect(mapStateToProps,mapDispatchToProps)(FavIcon)
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
backgroundColor: '#fff',
alignItems: 'flex-start',
justifyContent: 'center',
},
favItem: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-start',
marginTop:10,
paddingTop:15,
paddingBottom:15,
marginLeft:30,
marginRight:30,
backgroundColor:'#00BCD4',
borderRadius:10,
borderWidth: 1,
borderColor: '#fff',
height: 75,
width: 300,
}
});
This if the reducer....the code enters the TOGGLE switch but the state is not updated with the new values.
import {TOGGLE, IS_FAVOURITE} from '../actions'
export const favids = (state=[], action) => {
const {type, recipeid} = action
const newRecipe = {
recipeid: recipeid,
is_fav: true,
}
switch (type) {
case TOGGLE: {
console.log(`Toggle State = ${JSON.stringify(state)}`)
console.log(`NEW REcipe ${JSON.stringify(newRecipe)} `)
// console.log(`Toggle State after adding = ${JSON.stringify(state)}`)
// return state.map(item=>{
// state.recipeid === recipeid ?
// {...item, newRecipe} : {...item,newRecipe}
// })
return {...state, newRecipe}
}
case IS_FAVOURITE: {
console.log(`Is Favourite state =${JSON.stringify(state)}`)
return state.map(item=>{
item.recipeid === recipeid ?
{...item, is_fav: !item.is_fav} : item
})
}
default:
return state
}
}
I've tried different methods of updating the state (see below) but the state is not updated.
I've commented out the older code which was not working
// return state.map(item=>{
// state.recipeid === recipeid ?
// {...item, newRecipe} : {...item,newRecipe}
// })
return {...state, newRecipe}
Any help would be appreciated.
This is the index.js file from the '../actions' folder
export const TOGGLE = 'TOGGLE'
export const toggleFavId = id => ({
type: 'TOGGLE',
recipeid: id
})
export const IS_FAVOURITE = 'IS_FAVOURITE'
export const isFavourite = id => (
{
type: 'IS_FAVOURITE',
recipeid: id
}
)
export const TOGGLE_FAV = 'TOGGLE_FAV'
export const toggleFav = id => ({
type: 'TOGGLE_FAV',
recipeid: id,
})
this is the VisibleFavicon.js file
import {connect} from 'react-redux'
import Favicon from '../components/favicon'
const mapStateToProps = state =>({
favids: state
})
const mapDispatchToProps = dispatch => ({
toggleFavIds: id => dispatch ({
type: 'TOGGLE',
id
}),
isFavourite : id => dispatch ({
type: 'IS_FAVOURITE',
id
}),
})
export default connect(mapStateToProps, mapDispatchToProps)(Favicon)
Try to get whole state of redux instead of state.favids and wherever you want to use that state you can access it like props.state.favids :
const mapStateToProps = (state) =>({
favids: state,
})
Heres the solution to the issue, this is the code for the reducer.
import { TOGGLE, IS_FAVOURITE } from '../actions'
export const favids = (state = [], action) => {
const { type, recipeid } = action
const newRecipe = {
recipeid,
is_fav: true,
}
switch (type) {
case TOGGLE: {
return state.findIndex(recipe => recipe.recipeid === recipeid) === -1 ?
[...state, newRecipe] :
state.map(recipe =>
recipe.recipeid === recipeid ?
{ ...recipe, is_fav: !recipe.is_fav } : recipe
)
}
default:
return state
}
}

React Native Failed to ImportScripts Error

I'm getting an ImportScripts error which means I'm not importing or exporting something correctly I'm guessing. I've narrowed it down to the import { getPath } from '~/redux/modules/camera' line. But I'm not sure why I get an error. I import connect so I have access to dispatch and then I import the getPath function. What else should I be doing? Thanks!
import React, { PropTypes, Component } from 'react';
import {
Dimensions,
StyleSheet,
Text,
TouchableHighlight,
View
} from 'react-native';
import Camera from 'react-native-camera'
import { connect } from 'react-redux'
import { getPath } from '~/redux/modules/camera'
class NimbusCamera extends Component {
static propTypes = {
navigator: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
}
state = {
camera: {
aspect: Camera.constants.Aspect.fill,
captureTarget: Camera.constants.CaptureTarget.disk,
type: Camera.constants.Type.front,
orientation: Camera.constants.Orientation.auto,
flashMode: Camera.constants.FlashMode.auto,
}
isRecording: false,
timeLeft: 30,
limitReached: false
}
render() {
console.log(this.props)
return (
<View style={styles.container}>
<Camera
ref={(cam) => {
this.camera = cam;
}}
style={styles.preview}
aspect={this.state.camera.aspect}
type={this.state.camera.type}
captureTarget={this.state.camera.captureTarget}
captureAudio={true}
flashMode={this.state.camera.flashMode}
>
<Text style={styles.capture} onPress={this.startRecording.bind(this)}>[CAPTURE]</Text>
<Text style={styles.capture} onPress={this.stopRecording.bind(this)}>[STOP_RECORDING]</Text>
</Camera>
</View>
);
}
startRecording = () => {
if (this.camera) {
this.camera.capture({mode: Camera.constants.CaptureMode.video})
.then((data) => console.log(data))
.catch(err => console.error(err));
this.setState({
isRecording: true
});
let timerId = setInterval(countdown, 1000);
function countdown() {
if (this.state.timeLeft === 0) {
clearTimeout(timerId);
this.setState({isRecording: false})
} else {
this.setState({timeLeft: this.state.timeLeft--})
}
}
}
}
stopRecording = () => {
if (this.camera) {
this.camera.stopCapture();
this.setState({
isRecording: false
});
}
}
}
export default connect()(NimbusCamera)
const styles = StyleSheet.create({
container: {
flex: 1
},
preview: {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center',
height: Dimensions.get('window').height,
width: Dimensions.get('window').width
},
capture: {
flex: 0,
backgroundColor: '#fff',
borderRadius: 5,
color: '#000',
padding: 10,
margin: 40
}
});
Here is my redux camera module.
const GET_PATH = 'GET_PATH'
const CLEAR_PATH = 'CLEAR_PATH'
initialState = {
videoPath: ''
}
export function getPath (path) {
return {
type: GET_PATH,
path
}
}
export function clearPath () {
return {
type: CLEAR_PATH
}
}
export default function camera (state = initialState, action) {
switch (action.type) {
case GET_PATH :
return {
...state,
videoPath: action.path
}
case CLEAR_PATH :
return {
...state,
videoPath: ''
}
default :
return state
}
}
Any log in your packager console? usually it print much more detail error info.
errors like these pops-up also when you make a typo in your code. Then module cannot be properly imported. Check your code for typos first :)

Resources