This question already has answers here:
How does connect work without mapDispatchToProps
(2 answers)
Closed 5 years ago.
I want to display the results of may api-call with react. My api returns a JSON Object:
0:{produkt_id: 1, produktname: "Bauernbrot", preis: "4"}
1:{produkt_id: 2, produktname: "Nussbrot", preis: "4.50"}
2:{produkt_id: 3, produktname: "Dinkelbrot", preis: "4.20"}
It works if my react component looks like that:
constructor() {
super();
this.state = {
bread: ' '
};
}
componentDidMount(){
axios
.post('/api/produkte')
.then((res)=> {
console.log(res.data);
this.setState(
{ bread: res.data.produkte[0].produktname }
);
})
.catch((err)=> {})
}
render(){
return (
<div>
<h1>{this.state.bread}</h1>
</div>
);
}
As I am using Redux, i would like to make that request with a redux-action. This action should update my "products" state in my redux store, that i will display in my react component. Unfortunately I can't get that working.
Here is my action:
import axios from 'axios';
import { GET_PRODUCTS } from './types';
export function setProducts(products) {
return {
type: GET_PRODUCTS,
products
};
}
export function updateProducts() {
return (dispatch) => {
return axios
.post('/api/produkte')
.then( res => {
console.log(res);
dispatch(setProducts(res.data.produkte[0].produktname));
})
.catch((err)=> {})
}
}
And my reducer (imported in root reducer):
import {GET_PRODUCTS} from '../actions/types';
const initialState = {
products: {}
};
export default (state=initialState,action = {}) => {
switch(action.type){
case GET_PRODUCTS:
return {
products: action.products
}
default: return state;
}
}
If i call my function "updateProducts()" in Constructor of my react component, I can't see that action being executed in my redux store. :(
import React from 'react';
import { connect } from 'react-redux';
import BestellForm from './BestellForm';
import { updateProducts } from '../../redux/actions/getProducts';
class BestellSeite extends React.Component {
render() {
return (
<BestellForm updateProducts={updateProducts}/>
);
}
}
export default connect (null, { updateProducts })(BestellSeite);
And:
import React, { Component } from 'react';
import './bestellSeite.css';
import moment from 'moment';
import axios from 'axios';
export default class BestellForm extends Component {
constructor() {
super();
this.state = {
bread: ' '
};
}
componentWillMount() {
this.props.updateProducts();
}
}
componentWillMount() {
this.props.dispatch(updateProducts());
}
did the trick
Related
I am very new to react native. The app I am developing has functional components.
Is there any way to convert class component to function component or convert this class into a function?
Is it possible to use functional and class component both in single app?
import React from 'react';
import DayPicker, { DateUtils } from 'react-day-picker';
import 'react-day-picker/lib/style.css';
export default class Example extends React.Component {
constructor(props) {
super(props);
this.handleDayClick = this.handleDayClick.bind(this);
this.state = {
selectedDays: [],
};
}
handleDayClick(day, { selected }) {
const { selectedDays } = this.state;
if (selected) {
const selectedIndex = selectedDays.findIndex(selectedDay =>
DateUtils.isSameDay(selectedDay, day)
);
selectedDays.splice(selectedIndex, 1);
} else {
selectedDays.push(day);
}
this.setState({ selectedDays });
}
render() {
return (
<div>
<DayPicker
selectedDays={this.state.selectedDays}
onDayClick={this.handleDayClick}
/>
</div>
);
}
}
Yes you can use both functional and class component in same time
import React, {useState} from "react";
import DayPicker, { DateUtils } from 'react-day-picker';
import 'react-day-picker/lib/style.css';
export default function Example(props = {}) {
// read about useState hooks, it replace state
const [selectedDays, setSelectedDays] = useState([]);
handleDayClick(day, { selected }) {
if (selected) {
const selectedIndex = selectedDays.findIndex(selectedDay =>
DateUtils.isSameDay(selectedDay, day)
);
selectedDays.splice(selectedIndex, 1);
} else {
selectedDays.push(day);
}
setSelectedDays( selectedDays );
}
render() {
return (
<div>
<DayPicker
selectedDays={ selectedDays}
onDayClick={handleDayClick}
/>
</div>
);
}
}
I am trying to create a React Native App thats trying to fetch the current location using the navigator.geolocation.getCurrentPosition function and i encounter the error 'Cannot read property 'getCurrentPosition' of undefined'
The following is the code that i use:
import update from "react-addons-update";
import constants from "./actionConstants";
//----------------------
//Constants
//----------------------
const { GET_CURRENT_LOCATION } = constants;
//----------------------
// Actions
//----------------------
export function getCurrentLocation(){
return(dispatch)=>{
navigator.geolocation.getCurrentPosition(
(position)=>{
dispatch({
type:GET_CURRENT_LOCATION,
payload:position
});
},
(error)=> console.log(error.message),
{enableHighAccuracy: true, timeout: 20000, maximumAge:1000}
);
}
}
//----------------------
// Action Handlers
//----------------------
function handleGetCurrentLocation(state, action){
return update(state,{
region:{
$set:action.payload
}
})
}
const ACTION_HANDLERS = {
GET_CURRENT_LOCATION:handleGetCurrentLocation
}
const initialState = {
region: {}
};
export function HomeReducer(state = initialState, action){
const handler = ACTION_HANDLERS[action.type];
return handler ? handler(state, action) : state;
}
My actionConstants.js file is:
export default {
GET_CURRENT_LOCATION:"GET_CURRENT_LOCATION"
};
This is being called in the following file :
import React from "react";
import {View, Text} from "react-native";
import MapContainer from "./MapContainer";
import {Container} from "native-base";
export default class Home extends React.Component{
componentDidMount(){
this.props.getCurrentLocation();
}
render(){
const region = {
latitude : 3.146642,
longitude : 101.695845,
latitudeDelta:0.0922,
longitudeDelta:0.0421
}
return(
<Container>
<MapContainer region={region}/>
</Container>
);
}
}
Could someone help.. Thanks in advance!!!
what is navigator ?
here is my working code
import Geolocation from 'react-native-geolocation-service';
componentWillMount() {
Geolocation.getCurrentPosition(
(position) => {
addLocation(position.coords);
},
(error) => {
console.error(error);
},
{ enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 },
);
}
where have you called getCurrentLocation? it seems you have not called it.
For me, this code works without importing any extra library:
import React, { Component } from 'react';
import {ToastAndroid } from 'react-native';
export default class location extends Component {
constructor(props) {
super(props);
this.state = {
};
}
getCurrentLocation(){
navigator.geolocation.getCurrentPosition((position) => {
ToastAndroid.show((position.coords.latitude + ', ' + position.coords.longitude),ToastAndroid.LONG);
}, function (e) {
ToastAndroid.show(e, ToastAndroid.SHORT)
}, {enableHighAccuracy: true, timeout: 20000, maximumAge:1000});
}
render() {
return (
<View>{this.getCurrentLocation()}</View>
);
}
}
I have the following the code like this.
import React, {Component} from 'react'
import {AsyncStorage} from 'react-native'
export default {
baseURL: 'http://mywebsite.com/JsonApi/',
};
In the code, I am using the base url for api calls. Now, sometimes, I want to add a sub domain to the domain. And, the sub domain values are taking from AsyncStorage. How can I modify the code to do that?
You can get value from Async storage and set that into state.
import * as React from 'react';
import { View } from 'react-native';
import { AsyncStorage } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
subdomain: '',
};
}
retrieveData = async () => {
try {
const value = await AsyncStorage.getItem('your subdomain stored key');
this.setState({ subdomain: value });
const baseURL = `http://${this.state.subdomain}.mywebsite.com/JsonApi/`;
} catch (error) {
console.log(error);
}
}
componentDidMount() {
this.retrieveData();
}
render() {
return (
<View/>
);
}
}
I'm working with redux-saga for the first time and I'm not having luck with it at the moment. I'm thinking my actions aren't being passed into my saga, but I'm not sure?? Below I've provided a sample of the code. I'm currently not passing in any API calls, just some functions to get this going.
App.js File:
import React from "react";
import Setup from "./src/boot/setup";
import { Provider } from 'react-redux';
import store from './src/store';
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<Setup/>
</Provider>
);
}
}
store.js
import {createStore, applyMiddleware} from 'redux';
import createSagaMiddleware from 'redux-saga';
import AllReducers from '../src/reducers';
import rootSaga from '../src/saga';
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
AllReducers,
applyMiddleware(sagaMiddleware)
);
sagaMiddleware.run(rootSaga);
export default store;
saga.js
import { call, put, takeEvery, takeLatest } from "redux-
saga/effects";
**import {receiveHelloWorld } from "./actions";
import { REQUEST_HELLO_WORLD } from "./actions/types";**
function* helloWorld(action) {
try {
yield put(receiveHelloWorld("Hello world from redux saga!"));
} catch (e) {
yield put(receiveHelloWorld("Hello world from redux saga!"));
}
}
export default function* rootSaga() {
yield takeLatest(REQUEST_HELLO_WORLD, helloWorld);
}
reducer.js
import { RECEIVE_HELLO_WORLD } from "../actions";
export default (state = "", { type, text = "" }) => {
switch (type) {
case RECEIVE_HELLO_WORLD:
return text;
default:
return state;
}
};
actionCreator.js (this is importing into the actions index.js file)
import { REQUEST_HELLO_WORLD, RECEIVE_HELLO_WORLD } from './types';
export const requestHelloWorld = () => ({
type: REQUEST_HELLO_WORLD
});
export const receiveHelloWorld = text => ({
type: RECEIVE_HELLO_WORLD, text
});
sagaScreen.js
import React, { Component } from "react";
import { Container, Text, Button } from "native-base";
import { connect } from "react-redux";
import styles from "../styles/styles";
import { bindActionCreators } from "redux";
import { requestHelloWorld } from "../actions";
class SagaScreen extends React.Component {
componentDidMount() {
this.props.requestHelloWorld();
}
render() {
return (
<Container style={styles.container}>
<Text style={{marginTop: 50 }}> {this.props.helloWorld} </Text>
</Container>
);
}
}
const mapStateToProps = state => ({ helloWorld: state.helloWorld });
const mapDispatchToProps = dispatch =>
bindActionCreators({ requestHelloWorld }, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)
(SagaScreen);
Update Your saga:
saga.js
import { REQUEST_HELLO_WORLD, RECEIVE_HELLO_WORLD } from "./actions/types";
function* helloWorld(action) {
try {
yield put({type: RECEIVE_HELLO_WORLD, text: "Hello world from redux saga!"});
} catch (e) {
//Handling for error
}
}
export default function* watchStartSaga () {
yield takeLatest(REQUEST_HELLO_WORLD, helloWorld);
}
//Updated Answer
Create new file. index.js in directory src/saga.
index.js
import { fork } from "redux-saga/effects";
import watchStartSaga from "./saga";
export default function* rootSaga() {
yield fork(watchStartSaga);
}
I have been following this tutorial to integrate redux into my react native app.
https://github.com/jlebensold/peckish
On my Home view, I'm not able to call the functions from my action folder.
One difference is that I'm using react-navigation in my app. Wonder if I need to integrate redux with react navigation to be able to use redux for all data?
Below is the full implementation code I have been doing.
On the Home screen, I call the fetchSite function on ComponentDidMount to launch an async call with axios. But I can't even access to this function.
Sorry for this long post but I can't figure out how to make this work so quite difficult to make a shorter code sample to explain the structure of my app.
Let me know if any question.
index.ios.js
import React from 'react'
import { AppRegistry } from 'react-native'
import { Provider } from 'react-redux'
import { createStore, applyMiddleware, compose} from 'redux'
import thunkMiddleware from 'redux-thunk'
import { createLogger } from 'redux-logger'
import reducer from './app/reducers'
import AppContainer from './app/index'
// middleware that logs actions
const loggerMiddleware = createLogger({ predicate: (getState, action) => __DEV__ });
function configureStore(initialState) {
const enhancer = compose(
applyMiddleware(
thunkMiddleware, // lets us dispatch() functions
loggerMiddleware,
),
);
return createStore(reducer, initialState, enhancer);
}
const store = configureStore({});
const App = () => (
<Provider store={store}>
<AppContainer />
</Provider>
);
AppRegistry.registerComponent('Appero', () => App;
reducers/index.js
import { combineReducers } from 'redux';
import * as sitesReducer from './sites'
export default combineReducers(Object.assign(
sitesReducer,
));
reducers/sites.js
import createReducer from '../lib/createReducer'
import * as types from '../actions/types'
export const searchedSites = createReducer({}, {
[types.SET_SEARCHED_SITES](state, action) {
let newState = {};
action.sites.forEach( (site) => {
let id = site.id;
newState[id] = Object.assign({}, site, { id });
});
return newState;
},
});
../lib/createReducer
export default function createReducer(initialState, handlers) {
return function reducer(state = initialState, action) {
if (handlers.hasOwnProperty(action.type)) {
return handlers[action.type](state, action)
} else {
return state
}
}
}
../actions/types
export const SET_SEARCHED_SITES = 'SET_SEARCHED_SITES';
AppContainer in ./app/index
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { ActionCreators } from './actions';
console.log(ActionCreators); //Properly gathered the functions from the actions folder
import { Root } from './config/router';
window.store = require('react-native-simple-store');
window.axios = require('axios');
class App extends Component {
render() {
return (
<Root />
)
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(ActionCreators, dispatch);
}
export default connect(mapDispatchToProps)(App);
ActionCreators in './actions';
import * as SiteActions from './sites'
export const ActionCreators = Object.assign({},
SiteActions,
);
Actions in './actions/sites'
import * as types from './types' //See above
export function fetchSites(token) {
return (dispatch, getState) => {
let instance = axios.create({
baseURL: url + 'api/',
timeout: 10000,
headers: {'Accept' : 'application/json', 'Authorization' : 'Bearer ' + token}
});
instance.get('/sites?page=1')
.then(response => {
console.log(response.data.data);
dispatch(setSearchedSites({sites: response.data.data}));
}).catch(error => {
console.log(error);
});
}
}
export function setSearchedSites({ sites }) {
return {
type: types.SET_SEARCHED_SITES,
sites,
}
}
Root file for navigation based on react-navigation
I made it as simple as possible for this example.
import React from 'react';
import {StackNavigator} from 'react-navigation';
import Home from '../screens/Home';
export const Root = StackNavigator({
Home: {
screen: Home,
}
});
And finally my Home screen
import React, {Component} from 'react';
import { connect } from 'react-redux';
import {Text, View} from 'react-native';
class Home extends Component {
componentDidMount()
{
let token = "12345678" //Just for this example
this.props.fetchSites(token).then( (response) => {
console.log(response);
});
}
render() {
return (
<View>
<Text>This is the Home view</text>
</View>
);
}
}
function mapStateToProps(state) {
return {
searchedSites: state.searchedSites
};
}
export default connect(mapStateToProps)(Home);
To use action methods you need to connect in home screen like this
import { fetchSites } from '<your-path>'
// your Home's other code.
const mapDispatchToProps = (dispatch) => {
return{
fetchSites:dispatch(fetchSites())
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Home);
after that you can use fetchSites as this.props.fetchSites whenever you want.