How can I get the right data from database with react - javascript

I made a page by using nodejs+react+redux.
I made a edit button in the page and want to edit my data.
Now I select KUMAMOTO-CTI and change the priority from 5 to 10.I use ajax to get data from database to fill the blank.Before I submit it I can get the right data from database.But when I change priority and click to edit it again.The filled data will be wrong.I have to refresh it to get the right data.
And sometimes it will become like this:Error
Could anybody tell me how to solve it?
Here is the pic:progress
Here is my code.
server.js
const Koa = require('koa')
const Router = require('koa-router')
const cors = require('koa2-cors')
const app = new Koa()
const router = new Router()
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import serversReducer from '../client/reducers/reducer'
import { renderToString } from 'react-dom/server'
const store = createStore(serversReducer)
const views = require('koa-views')
const co = require('co')
const convert = require('koa-convert')
const json = require('koa-json')
const onerror = require('koa-onerror')
const bodyparser = require('koa-bodyparser')
const logger = require('koa-logger')
const debug = require('debug')('koa2:server')
const path = require('path')
//const ReactDOMServer = require('react-dom/server')
const React = require('react')
const config = require('./config')
const routes = require('./routes')
const mongoose = require('mongoose')
const stateSchema = require('./models/State')
const mission = require('./models/port')
const port = process.env.PORT || config.port
import Main from '../client/containers/Main'
mongoose.connect('mongodb://127.0.0.1:27017/monitor', {
useMongoClient: true
});
mongoose.Promise = global.Promise;
var State = mongoose.model("State", stateSchema);
// error handler
onerror(app)
// middlewares
app.use(bodyparser())
.use(json())
.use(logger())
.use(cors())
.use(require('koa-static')(__dirname + '/public'))
.use(views(path.join(__dirname, '/views'), {
options: {
settings: {
views: path.join(__dirname, 'views')
}
},
map: {
'ejs': 'ejs'
},
extension: 'ejs'
}))
.use(router.routes())
.use(router.allowedMethods())
// logger
app.use(async(ctx, next) => {
const start = new Date()
await next()
const ms = new Date() - start
console.log(`${ctx.method} ${ctx.url} - $ms`)
})
router.get('/', async(ctx, next) => {
const staticMarkup = await renderToString(
<Provider store={store}>
<Main />
</Provider>
)
const preloadedState = store.getState();
//console.log(preloadedState);
await ctx.render('index', {
reduxData: preloadedState,
helloComponentMarkup: staticMarkup
})
})
router.post('/show', async(ctx, next) => {
ctx.body = 'ok';
let newArray = [];
await State.find({}, function(err, doc) {
if (err) {
return;
}
doc.forEach(function(element, index) {
newArray.push(element);
})
ctx.response.body = JSON.stringify(newArray);
}).sort({
priority: 1
})
})
router.post('/edit', async(ctx, next) => {
ctx.body = 'ok'
await State.update({
_id: ctx.request.body.querymark
}, {
$set: {
server_name: ctx.request.body.servername,
jp_name: ctx.request.body.jpname,
ip_address: ctx.request.body.ipaddress,
port: ctx.request.body.port,
priority: ctx.request.body.priority
}
}, function(err, doc) {
if (err) {
return;
}
})
})
router.post('/create', async(ctx, next) => {
ctx.body = 'ok'
await new State({
server_name: ctx.request.body.servername,
jp_name: ctx.request.body.jpname,
ip_address: ctx.request.body.ipaddress,
port: ctx.request.body.port,
priority: ctx.request.body.priority
}).save(function(err) {
if (err)
console.log(err.toString());
})
})
router.post('/delete', async(ctx, next) => {
ctx.body = 'ok'
await State.remove({
_id: ctx.request.body.id
}, function(err, doc) {
if (err) {
return;
}
});
})
routes(router)
app.on('error', function(err, ctx) {
console.log(err)
logger.error('server error', err, ctx)
})
module.exports = app.listen(config.port, () => {
console.log(`Listening on http://localhost:${config.port}`)
console.log(__dirname);
})
ListContainer.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { Router, Route, hashHistory } from 'react-router'
import { Segment, Icon, Table, Modal, Button, Form } from 'semantic-ui-react'
const axios = require('axios')
class ListContainer extends Component {
static propTypes = {
test_data: PropTypes.object.isRequired,
post_data: PropTypes.object.isRequired,
onDeleteServer: PropTypes.func,
onEditServer: PropTypes.func,
initServers: PropTypes.func,
index: PropTypes.number
}
constructor(props) {
super(props)
this.state = ({
servername: props.post_data.server_name,
jpname: props.post_data.jp_name,
ipaddress: props.post_data.ip_address,
port: props.post_data.port,
priority: props.post_data.priority
})
}
static defaultProps = {
servers: []
}
handleDeleteServer(index) {
if (this.props.onDeleteServer) {
this.props.onDeleteServer(this.props.index)
} else {
console.log("error")
}
}
/*handleEditServer(index) {
if (this.props.onEditServer) {
this.props.onEditServer(this.props.index)
} else {
console.log("error")
}
this.setState({
open: false
})
}*/
handleServerNameChange(event) {
this.setState({
servername: event.target.value
})
}
handleJPNameChange(event) {
this.setState({
jpname: event.target.value
})
}
handleIPChange(event) {
this.setState({
ipaddress: event.target.value
})
}
handlePORTChange(event) {
this.setState({
port: event.target.value
})
}
handlePriorityChange(event) {
this.setState({
priority: event.target.value
})
}
handleSubmit(index) {
axios.post('/edit', {
querymark: this.props.post_data._id,
servername: this.state.servername,
jpname: this.state.jpname,
ipaddress: this.state.ipaddress,
port: this.state.port,
priority: this.state.priority
}).then((response) => {
var new_data;
if (response.data.success === false) {
alert("error")
} else {
window.location.reload();
//console.log(this.props.post_data)
dispatch(onEditServer(index, {
querymark: this.props.post_data._id,
servername: this.state.servername,
jpname: this.state.jpname,
ipaddress: this.state.ipaddress,
port: this.state.port,
priority: this.state.priority
}))
}
}).catch(() => {
})
this.setState({
open: false
})
}
state = {
open: false
}
show = (size, dimmer) => () => this.setState({
size,
dimmer,
open: true
})
close = () => this.setState({
open: false
})
render() {
const {open, size, dimmer} = this.state
const post_data = this.props.post_data
var updated_time = (new Date(post_data.updated_at)).toLocaleString().replace('/T/', '').replace('/\../+', '')
var state_color = (post_data.state == "green") ? "green" : "red"
var icon_name = (post_data.state == "green") ? "smile" : "warning sign"
return (
<Table.Row>
<Table.Cell><Icon name={icon_name} color={state_color}/></Table.Cell>
<Table.Cell>{post_data.jp_name}</Table.Cell>
<Table.Cell>{post_data.ip_address}</Table.Cell>
<Table.Cell>{post_data.port}</Table.Cell>
<Table.Cell>{updated_time}</Table.Cell>
<Table.Cell>{post_data.priority}</Table.Cell>
<Table.Cell>
<div>
<Icon link name='settings' color='purple' onClick={this.show('small', 'blurring')} />
<Modal size={size} dimmer={dimmer} open={open} onClose={this.close} closeIcon>
<Modal.Header>Edit</Modal.Header>
<Modal.Content>
<Modal.Description>
<Form>
<Form.Group width='equal'>
<Form.Field>
<label>Server Name</label>
<input value={this.state.servername} onChange={this.handleServerNameChange.bind(this)} />
</Form.Field>
<Form.Field>
<label>JP Name</label>
<input value={this.state.jpname} onChange={this.handleJPNameChange.bind(this)} />
</Form.Field>
</Form.Group>
<Form.Group width='equal'>
<Form.Field>
<label>IP Address</label>
<input value={this.state.ipaddress} onChange={this.handleIPChange.bind(this)} />
</Form.Field>
<Form.Field>
<label>Priority</label>
<input value={this.state.priority} onChange={this.handlePriorityChange.bind(this)} />
</Form.Field>
</Form.Group>
<Form.Group>
<Form.Field>
<label>Port</label>
<input value={this.state.port} onChange={this.handlePORTChange.bind(this)} />
</Form.Field>
</Form.Group>
</Form>
</Modal.Description>
</Modal.Content>
<Modal.Actions>
<Button color='black' onClick={this.close}>
Nope
</Button>
<Button positive icon='checkmark' labelPosition='right' content="Submit" onClick={this.handleSubmit.bind(this)} />
</Modal.Actions>
</Modal>
</div>
</Table.Cell>
<Table.Cell><Icon link name='trash' color='purple' onClick={this.handleDeleteServer.bind(this)} /></Table.Cell>
</Table.Row>
)
}
}
const mapStateToProps = (state) => {
return {
servers: state.servers
}
}
const mapDispatchToProps = (dispatch) => {
return {
onEditServer: (index, data) => {
dispatch(editServer(index, data))
},
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(ListContainer)
SegmentContainer.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { Container, Loader, Table, Grid, Icon, Button, Modal, Form } from 'semantic-ui-react'
import SegmentList from '../components/SegmentContainer'
import { initServers, deleteServer, editServer } from '../reducers/reducer'
import MenuFix from '../components/Menu'
const axios = require('axios')
class SegmentContainer extends Component {
static propTypes = {
servers: PropTypes.array,
initServers: PropTypes.func,
onDeleteServer: PropTypes.func,
onAddServer: PropTypes.func
}
constructor() {
super()
//this._loadData()
this.state = {
servername: '',
jpname: '',
ipaddress: '',
priority: ''
}
}
componentWillMount() {
this._loadData()
}
componentDidMount() {
if (this.timer) {
clearInterval(this.timer)
}
this.timer = setInterval(() => {
this._loadData()
}, 3000)
}
componentWillUnmount() {
clearInterval(this.timer)
}
_loadData() {
let sorted_data = [];
let posts_data = [];
let response = axios.post('/show')
.then((response) => {
Object.keys(response.data).forEach(function(index) {
sorted_data.push(response.data[index]);
})
function _dataCompare(a, b) {
if (a.priority > b.priority)
return 1;
if (a.priority < b.priority)
return -1;
return 0;
}
sorted_data.forEach((item, index) => {
posts_data.push(item);
})
posts_data.sort(_dataCompare);
this.props.initServers(posts_data)
//dispatch(initServers(posts_data))
}).catch(() => {
})
}
handleDeleteServer(index) {
const {servers} = this.props
axios.post('/delete', {
id: servers[index]._id
}).then((response) => {
if (response.data.success === false) {
alert("error");
} else {
window.location.reload();
}
}).catch(() => {
})
if (this.props.onDeleteServer) {
this.props.onDeleteServer(index)
}
}
/*handleEditServer(index) {
const {servers} = this.props
axios.post('/edit', {
querymark: this.props.servers._id,
servername: this.state.servername,
jpname: this.state.jpname,
ipaddress: this.state.ipaddress,
port: this.state.port,
priority: this.state.priority
}).then((response) => {
if (response.data.success === false) {
alert("error")
} else {
//window.location.reload();
dispatch(onEditServer(index, {
querymark: this.props.servers._id,
servername: this.state.servername,
jpname: this.state.jpname,
ipaddress: this.state.ipaddress,
port: this.state.port,
priority: this.state.priority
}))
}
}).catch(() => {
})
this.setState({
open: false
})
}*/
handleCreate(server) {
axios.post('/create', {
servername: this.state.servername,
jpname: this.state.jpname,
ipaddress: this.state.ipaddress,
port: this.state.port,
priority: this.state.priority
}).then((response) => {
if (response.data.success === false) {
alert("error");
} else {
window.location.reload()
dispatch(onAddServer(index, {
servername: this.state.servername,
jpname: this.state.jpname,
ipaddress: this.state.ipaddress,
port: this.state.port,
priority: this.state.priority
}))
}
}).catch(() => {
})
this.setState({
open: false
})
}
handleServerNameChange(event) {
this.setState({
servername: event.target.value
})
}
handleJPNameChange(event) {
this.setState({
jpname: event.target.value
})
}
handleIPChange(event) {
this.setState({
ipaddress: event.target.value
})
}
handlePORTChange(event) {
this.setState({
port: event.target.value
})
}
handlePriorityChange(event) {
this.setState({
priority: event.target.value
})
}
state = {
open: false
}
show = (size, dimmer) => () => this.setState({
size,
dimmer,
open: true
})
close = () => this.setState({
open: false
})
render() {
const {open, size, dimmer} = this.state
return (
<Grid>
<MenuFix />
<Container style = {{
marginTop: '6em'
}}>
<Table unstackable>
<Table.Header>
<Table.Row>
<Table.HeaderCell colSpan='8'>
<Button basic color='violet' floated='right' icon labelPosition='left' primary size='tiny' onClick={this.show('small', 'blurring')}>
<Icon link color='violet' name='add' />Add
</Button>
<Modal size={size} dimmer={dimmer} open={open} onClose={this.close} closeIcon>
<Modal.Header>Add</Modal.Header>
<Modal.Content>
<Modal.Description>
<Form>
<Form.Group width='equal'>
<Form.Field>
<label>Server Name</label>
<input value={this.state.servername} onChange={this.handleServerNameChange.bind(this)} />
</Form.Field>
<Form.Field>
<label>JP Name</label>
<input value={this.state.jpname} onChange={this.handleJPNameChange.bind(this)} />
</Form.Field>
</Form.Group>
<Form.Group width='equal'>
<Form.Field>
<label>IP Address</label>
<input value={this.state.ipaddress} onChange={this.handleIPChange.bind(this)} />
</Form.Field>
<Form.Field>
<label>Priority</label>
<input value={this.state.priority} onChange={this.handlePriorityChange.bind(this)} />
</Form.Field>
</Form.Group>
<Form.Group>
<Form.Field>
<label>Port</label>
<input value={this.state.port} onChange={this.handlePORTChange.bind(this)} />
</Form.Field>
</Form.Group>
</Form>
</Modal.Description>
</Modal.Content>
<Modal.Actions>
<Button color='black' onClick={this.close}>
Nope
</Button>
<Button positive icon='checkmark' labelPosition='right' content="Submit" onClick={this.handleCreate.bind(this)} />
</Modal.Actions>
</Modal>
</Table.HeaderCell>
</Table.Row>
<Table.Row>
<Table.HeaderCell>State<Loader active inline size='small' /></Table.HeaderCell>
<Table.HeaderCell>Server Name</Table.HeaderCell>
<Table.HeaderCell>IP Address</Table.HeaderCell>
<Table.HeaderCell>Port</Table.HeaderCell>
<Table.HeaderCell>Updated</Table.HeaderCell>
<Table.HeaderCell>Priority</Table.HeaderCell>
<Table.HeaderCell>Edit</Table.HeaderCell>
<Table.HeaderCell>Delete</Table.HeaderCell>
</Table.Row>
</Table.Header>
<SegmentList posts_data = {this.props.servers} onDeleteServer={this.handleDeleteServer.bind(this)} />
</Table>
</Container>
</Grid>
)
}
}
const mapStateToProps = (state) => {
return {
servers: state.servers
}
}
const mapDispatchToProps = (dispatch) => {
return {
initServers: (servers) => {
dispatch(initServers(servers))
},
onDeleteServer: (index) => {
dispatch(deleteServer(index))
},
onEditServer: (index, data) => {
dispatch(editServer(index, data))
},
onAddServer: (server) => {
dispatch(addServer(server))
}
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(SegmentContainer)
reducer.js
//action types
const INIT_SERVERS = 'INIT_SERVERS'
const ADD_SERVER = 'ADD_SERVER'
const DELETE_SERVER = 'DELETE_SERVER'
const EDIT_SERVER = 'EDIT_SERVER'
//reducer
export default function(state, action) {
if (!state) {
state = {
servers: []
}
}
switch (action.type) {
case INIT_SERVERS:
return {
servers: action.servers
}
case ADD_SERVER:
return {
servers: [...state.servers, action.server]
}
case EDIT_SERVER:
return {
servers: [...state.servers.slice(0, action.index), Object.assign({}, state.servers[action.index], {
done: true
}), ...state.servers.slice(action.index + 1)]
/*servers: Object.assign([...state.servers], {
[index]: action.data
})*/
//servers: Object.assign({}, state[action.index], action.data)
}
case DELETE_SERVER:
return {
servers: [
...state.servers.slice(0, action.index),
...state.servers.slice(action.index + 1)
]
}
default:
return state
}
}
// action creators
export const initServers = (servers) => {
return {
type: INIT_SERVERS,
servers
}
}
export const addServer = (server) => {
return {
type: ADD_SERVER,
server
}
}
export const deleteServer = (index) => {
return {
type: DELETE_SERVER,
index
}
}
export const editServer = (index, data) => {
return {
type: EDIT_SERVER,
index,
data
}
}
SegmentList.js
import React, { Component, PropTypes } from 'react'
import ListContainer from '../containers/ListContainer'
export default class SegmentList extends Component {
static propTypes = {
posts_data: PropTypes.array,
onDeleteServer: PropTypes.func,
//onEditServer: PropTypes.func
}
static defaultProps = {
posts_data: []
}
handleDeleteServer(index) {
if (this.props.onDeleteServer) {
this.props.onDeleteServer(index)
}
}
/*handleEditServer(index) {
if (this.props.onEditServer) {
this.props.onEditServer(index)
}
}*/
render() {
return (
<div>
{this.props.posts_data.map((data, i) => <ListContainer
post_data={data}
key={i}
index={i} onDeleteServer={this.handleDeleteServer.bind(this)} />
)}
</div>
)
}
}

First of all, react is for SPA, if you use reload just use HTTP (no ajax) to edit. Here is solution for SPA
before coding, the main idea is to update your data after edit, so the road map should be:
1.fetch an array from server and store into state.servers, and it should be a list of plain objects that contain your server info
2.when you update, you should apply the update to server and then update to local store, as you did in create/delete, edit is most likely the same thing with more data
then your handleSubmit should be (notice index from iteration as param)
//index from iteration, should be passed from parent component
handleSubmit(index) {
const data = {
querymark: this.props.post_data._id,
servername: this.state.servername,
jpname: this.state.jpname,
ipaddress: this.state.ipaddress,
port: this.state.port,
priority: this.state.priority
}
axios.post('/edit', data).then((response) => {
if (response.data.success === false) {
alert("error");
} else {
//window.location.reload();
dispatch(onEditServer(index,data))
}
}).catch(() => {})
this.setState({
open: false
})
}
onEditServer should be
const mapDispatchToProps = (dispatch) => {
return {
initServers: (servers) => {
dispatch(initServers(servers))
},
onDeleteServer: (serverIndex) => {
dispatch(deleteServer(serverIndex))
},
onEditServer: (index, data) => {
dispatch(editServer({
type: 'edit',
index,
data,
}))
},
onAddServer: (server) => {
dispatch(addServer(server))
}
}
}
edit reducer
// edit reducer
const edit = (state, action) {
state.servers[action.index] = actions.data
return state
}
then changes will take effect automatically

Related

Sending multipart Form in ReactJS vs Postman

I've created a registration api that works fine using postman, I added some values there plus image an everything stores correctly, data an image, Later I started my React form and only text works, image is not currently sent to the api I guess.
Doing console.log() api in Node:
console.log(req.files);
with React Form: []
with Postman: an array of object that perfectly works
req.files output using postman
{
fieldname: 'images',
originalname: 'Screen Shot 2021-02-22 at 17.18.41.png',
encoding: '7bit',
mimetype: 'image/png',
destination: 'uploads/',
filename: '091f77f82fb805b1ede9f23205cc578e',
path: 'uploads/091f77f82fb805b1ede9f23205cc578e',
size: 37052
}
Here's my react classes:
httpService.js
import axios from "axios";
import { toast } from "react-toastify";
axios.interceptors.response.use(null, (error) => {
const expectedError =
error.response &&
error.response.status >= 400 &&
error.response.status < 500;
if (!expectedError) {
console.log("Loggind the error: ", error);
toast("An unexpected error ocurred.");
}
return Promise.reject(error);
});
export default {
post: axios.post
};
itemService.js
export function saveItem(item) {
const headers = {
'Content-Type': 'multipart/form-data',
};
return http.post(MY_ENDPOINT, item, headers);
}
itemForm.js
import React from "react";
import Joi from "joi-browser";
import Form from "./common/form";
import { saveItem } from "../services/itemService";
class ItemForm extends Form {
state = {
data: { title: "", description: "", category: "", images: "" },
categories: [],
errors: {},
};
schema = {
_id: Joi.string(),
title: Joi.string().required().label("Title"),
description: Joi.string().required().label("Description"),
category: Joi.string().required().label("Category"),
images: Joi.required().label("Image"),
};
doSubmit = async () => {
console.log('form data> ', this.state.data); // This shows the correct object.
let formData = new FormData();
formData.append('title', this.state.data.title);
formData.append('description', this.state.data.description);
formData.append('category', this.state.data.category);
formData.append('images', this.state.data.images);
try {
await saveItem(formData);
} catch (ex) {
}
};
render() {
return (
<div>
<h1>New item</h1>
<form onSubmit={this.handleSubmit}>
{this.renderInput("title", "Title")}
{this.renderInput("description", "Description")}
{this.renderSelect(
"category",
"title",
"Category",
this.state.categories
)}
{this.renderInputFile("images", "images", "file", false)}
{this.renderButton("Register")}
</form>
</div>
);
}
}
export default ItemForm;
form.jsx (The extended class)
import React, { Component } from "react";
import Joi from "joi-browser";
import Input from "./input";
import Select from "./select";
class Form extends Component {
state = {
data: {},
errors: {},
};
validate = () => {
const options = { abortEarly: false };
const { error } = Joi.validate(this.state.data, this.schema, options);
if (!error) return null;
const errors = {};
for (let item of error.details) errors[item.path[0]] = item.message;
return errors;
};
validateProperty = ({ name, value }) => {
const obj = { [name]: value };
const schema = { [name]: this.schema[name] };
const { error } = Joi.validate(obj, schema);
return error ? error.details[0].message : null;
};
handleSubmit = (e) => {
e.preventDefault();
const errors = this.validate();
this.setState({ errors: errors || {} });
if (errors) return;
this.doSubmit();
};
handleChange = ({ currentTarget: input }) => {
const errors = { ...this.state.errors };
const errorMessage = this.validateProperty(input);
if (errorMessage) errors[input.name] = errorMessage;
else delete errors[input.name];
const data = { ...this.state.data };
data[input.name] = input.value;
this.setState({ data, errors });
};
handleInputFileChange = ({ currentTarget: input }) => {
const errors = { ...this.state.errors };
const errorMessage = this.validateProperty(input);
if (errorMessage) errors[input.name] = errorMessage;
else delete errors[input.name];
const data = { ...this.state.data };
data[input.name] = input.value;
this.setState({ data, errors });
};
renderButton(label) {
return (
<button className="btn btn-primary" disabled={this.validate()}>
{label}
</button>
);
}
renderInput(name, label, type = "text", multiple = false) {
const { data, errors } = this.state;
return (
<Input
type={type}
name={name}
value={data[name]}
label={label}
onChange={this.handleChange}
error={errors[name]}
multiple={multiple}
/>
);
}
renderSelect(name, contentField, label, options) {
const { data, errors } = this.state;
return (
<Select
name={name}
value={data[name]}
label={label}
contentField={contentField}
options={options}
onChange={this.handleChange}
error={errors[name]}
/>
);
}
renderInputFile(name, label, type = "text", multiple = false) {
const { data, errors } = this.state;
return (
<Input
type={type}
name={name}
value={data[name]}
label={label}
onChange={this.handleInputFileChange}
error={errors[name]}
multiple={multiple}
accept="image/*"
/>
);
}
}
export default Form;

Uncaught TypeError: Cannot convert undefined or null to object React JS

I am trying to get my photo blog/phlog manager component functional. However the console says the there an undefined object through props.
import React, { Component } from 'react';
import axios from 'axios';
import DropzoneComponent from 'react-dropzone-component';
import "../../../node_modules/react-dropzone-component/styles/filepicker.css";
import "../../../node_modules/dropzone/dist/min/dropzone.min.css";
class PhlogEditor extends Component {
constructor(props) {
super(props);
this.state = {
id: '',
phlog_status: '',
phlog_image: '',
editMode: false,
position: '',
apiUrl: 'http://127.0.0.1:8000/phlogapi/phlog/',
apiAction: 'post'
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.componentConfig = this.componentConfig.bind(this);
this.djsConfig = this.djsConfig.bind(this);
this.handlePhlogImageDrop = this.handlePhlogImageDrop.bind(this);
this.deleteImage = this.deleteImage.bind(this);
this.phlogImageRef = React.createRef();
}
deleteImage(event) {
event.preventDefault();
axios
.delete(
`http://127.0.0.1:8000/phlogapi/phlog/${this.props.id}/delete`,
{ withCredentials: true }
)
.then(response => {
this.props.handlePhlogImageDelete();
})
.catch(error => {
console.log('deleteImage failed', error)
});
}
The error is occuring at Object.keys(this.props.phlogToEdit).length>0
componentDidUpdate() {
if (Object.keys(this.props.phlogToEdit).length > 0) {
// debugger;
const {
id,
phlog_image,
phlog_status,
position
} = this.props.phlogToEdit;
this.props.clearPhlogsToEdit();
this.setState({
id: id,
phlog_image: phlog_image || '',
phlog_status: phlog_status || '',
position: position || '',
editMode: true,
apiUrl: `http://127.0.0.1:8000/phlogapi/phlog/${this.props.id}/update`,
apiAction: 'patch'
});
}
}
handlePhlogImageDrop() {
return {
addedfile: file => this.setState({ phlog_image_url: file })
};
}
componentConfig() {
return {
iconFiletypes: [".jpg", ".png"],
showFiletypeIcon: true,
postUrl: "https://httpbin.org/post"
};
}
djsConfig() {
return {
addRemoveLinks: true,
maxFiles: 3
};
}
buildForm() {
let formData = new FormData();
formData.append('phlog[phlog_status]', this.state.phlog_status);
if (this.state.phlog_image) {
formData.append(
'phlog[phlog_image]',
this.state.phlog_image
);
}
return formData;
}
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
handleSubmit(event) {
axios({
method: this.state.apiAction,
url: this.state.apiUrl,
data: this.buildForm(),
withCredentials: true
})
.then(response => {
if (this.state.phlog_image) {
this.phlogImageRef.current.dropzone.removeAllFiles();
}
this.setState({
phlog_status: '',
phlog_image: ''
});
if (this.props.editMode) {
this.props.handleFormSubmission(response.data);
} else {
this.props.handleSuccessfulFormSubmission(response.data);
}
})
.catch(error => {
console.log('handleSubmit for phlog error', error);
});
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit} className='phlog-editor-wrapper'>
<div className='one-column'>
<div className='image-uploaders'>
{this.props.editMode && this.props.phlog_image_url ? (
<div className='phlog-manager'>
<img src={this.props.phlog.phlog_image_url} />
<div className='remove-image-link'>
<a onClick={() => this.deleteImage('phlog_image')}>
Remove Photos
</a>
</div>
</div>
) : (
<DropzoneComponent
ref={this.phlogImageRef}
config={this.componentConfig()}
djsConfig={this.djsConfig()}
eventHandlers={this.handlePhlogImageDrop()}
>
<div className='phlog-msg'>Phlog Photo</div>
</DropzoneComponent>
)}
</div>
<button className='btn' type='submit'>Save</button>
</div>
</form>
);
}
}
export default PhlogEditor;
I do not understand how the object is empty when the props are coming from the parent component
phlog-manager.js:
import React, { Component } from "react";
import axios from "axios";
import PhlogEditor from '../phlog/phlog-editor';
export default class PhlogManager extends Component {
constructor() {
super();
Here I define phlogToEdit as an object to pass as props to phlogEditor child component
this.state = {
phlogItems: [],
phlogToEdit: {}
};
this.handleNewPhlogSubmission = this.handleNewPhlogSubmission.bind(this);
this.handleEditPhlogSubmission = this.handleEditPhlogSubmission.bind(this);
this.handlePhlogSubmissionError = this.handlePhlogSubmissionError.bind(this);
this.handleDeleteClick = this.handleDeleteClick.bind(this);
this.handleEditClick = this.handleEditClick.bind(this);
this.clearPhlogToEdit = this.clearPhlogToEdit.bind(this);
}
clearPhlogToEdit() {
this.setState({
phlogToEdit: {}
});
}
handleEditClick(phlogItem) {
this.setState({
phlogToEdit: phlogItem
});
}
handleDeleteClick(id) {
axios
.delete(
`http://127.0.0.1:8000/phlogapi/phlog/${id}`,
{ withCredentials: true }
)
.then(response => {
this.setState({
phlogItems: this.state.phlogItems.filter(item => {
return item.id !== id;
})
});
return response.data;
})
.catch(error => {
console.log('handleDeleteClick error', error);
});
}
handleEditPhlogSubmission() {
this.getPhlogItems();
}
handleNewPhlogSubmission(phlogItem) {
this.setState({
phlogItems: [phlogItem].concat(this.state.phlogItems)
});
}
handlePhlogSubmissionError(error) {
console.log('handlePhlogSubmissionError', error);
}
getPhlogItems() {
axios
.get('http://127.0.0.1:8000/phlogapi/phlog',
{
withCredentials: true
}
)
.then(response => {
this.setState({
phlogItems: [...response.data]
});
})
.catch(error => {
console.log('getPhlogItems error', error);
});
}
componentDidMount() {
this.getPhlogItems();
}
render() {
return (
<div className='phlog-manager'>
<div className='centered-column'>
This is where the object, phlogToEdit is being passed as props to child component mentioned
<PhlogEditor
handleNewPhlogSubmission={this.handleNewPhlogSubmission}
handleEditPhlogSubmission={this.handleEditPhlogSubmission}
handlePhlogSubmissionError={this.handleEditPhlogSubmission}
clearPhlogToEdit={this.clearPhlogToEdit}
phlogToEdit={this.phlogToEdit}
/>
</div>
</div>
);
}
}
#Jaycee444 solved the problem it was the parent component!
phlogToEdit={this.state.phlogToEdit}

How to Load AsyncStorage Data on App Load and set to context in Expo?

I created an Expo project and I am setting some data to LocalStorage using AsyncStorage.
I want to reload that data on App start and want to assign that data to context/State.
How I can achieve that any one can help me to solve this problem.
here is my code of app.js
import React from 'react';
import { Asset } from 'expo-asset';
import * as Font from 'expo-font';
import { AppLoading } from 'expo';
....
const client = new ApolloClient({
// link: new HttpLink({
uri:'',
request: (operation) => {
getToken().then(token=>{
console.log('APIToken:', token);
operation.setContext({
headers: {
'api-token': token ? `${token}` : ''
}
})
});
},
//}),
cache: new InMemoryCache(),
});
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fffef9',
},
});
export default class App extends React.Component {
constructor(props) {
super(props);
this.updateContext=(key, value)=>{
this.setState({
[key]: value
});
};
this.updateStack=(stack)=>{
this.setState({
activeStack: stack
});
};
this.loadUsers=(users, _activeUser)=>{
console.log('Users:', users);
this.setState({
users: users,
activeUser: _activeUser
});
};
this.logOutUser=()=>{
this.setState({
activeUser: {},
users:[],
activeStack:'Auth'
});
};
this.state = {
isReady: false,
activeUser:{},
users: [],
activeStack:'Auth',
updateStack: this.updateStack,
updateContext: this.updateContext,
loadUsers: this.loadUsers,
logOutUser: this.logOutUser
};
}
render() {
if (!this.state.isReady) {
return (
<AppLoading
startAsync={this._cacheResourcesAsync}
onFinish={(res) => {this.setState({ isReady: true })}}
onError={console.warn}
/>
); }
return (
<ApolloProvider client={client}>
<SafeAreaProvider>
<SafeAreaView forceInset={{ bottom: 115 }} style={styles.container}>
{Platform.OS === 'ios' && <StatusBar barStyle="default" />}
<AppContext.Provider value={this.state}>
<AppNavigator/>
</AppContext.Provider>
</SafeAreaView>
</SafeAreaProvider>
</ApolloProvider>
);
}
async _cacheResourcesAsync() {
await Promise.all([
Asset.loadAsync([
// require('./assets/images/robot-dev.png'),
]),
Font.loadAsync({
'body': require('./assets/fonts/Archivo-Regular.ttf'),
'body-bold': require('./assets/fonts/Archivo-SemiBold.ttf'),
'headline': require('./assets/fonts/Nunito-Medium.ttf'),
'headline-bold': require('./assets/fonts/Nunito-Bold.ttf'),
'headline-extra-bold': require('./assets/fonts/Nunito-ExtraBold.ttf'),
})
]);
}
}
I have a function to loaduser() in a separate file, where i am loading users from localstorage and returning a promise. You can tell me where i should call loadUser() and handle its promise to loadState.
Thanks
I had the same problem. My solution was create another Component.
My App.js:
export default () => {
const [isReady, setIsReady] = useState(false);
const loadAssetsAsync = async () => {
const imageAssets = cacheImages([
require('./assets/images/bg_screen1.jpg'),
require('./assets/images/bg_screen2.jpg'),
require('./assets/images/bg_screen3.jpg'),
require('./assets/images/bg_screen4.jpg'),
require('./assets/images/user-cool.png'),
require('./assets/images/user-hp.png'),
require('./assets/images/user-student.png'),
require('./assets/images/avatar1.jpg'),
]);
const fontAssets = cacheFonts([
...vectorFonts,
{ georgia: require('./assets/fonts/Georgia.ttf') },
{ regular: require('./assets/fonts/Montserrat-Regular.ttf') },
{ light: require('./assets/fonts/Montserrat-Light.ttf') },
{ bold: require('./assets/fonts/Montserrat-Bold.ttf') },
{ UbuntuLight: require('./assets/fonts/Ubuntu-Light.ttf') },
{ UbuntuBold: require('./assets/fonts/Ubuntu-Bold.ttf') },
{ UbuntuLightItalic: require('./assets/fonts/Ubuntu-Light-Italic.ttf') },
]);
await Promise.all([...imageAssets, ...fontAssets]);
};
if (!isReady) {
return (
<AppLoading
startAsync={loadAssetsAsync}
onFinish={() => setIsReady(true)}
onError={console.warn}
/>
);
}
return <RootNavigator />;
};
My RootNavigator:
export default () => {
const [loaded, setLoaded] = useState(false);
const [init, setInit] = useState(false);
useEffect(() => {
const fetchData = async () => {
const type = await getUserType()
const name = await getName()
const UID = await getUID()
const token = await getToken()
if (!type || !name || !UID || !token) {
inital = 'Login'
} else if (type === 'CLIENT') {
inital = 'Client'
} else if (type === 'EMPLOYEEE') {
inital = 'Employee'
}
setInit(inital)
}
fetchData()
}, [])
function returnRoute() {
AppNavigator = createStackNavigator({
Login: {
screen: LoginScreen,
navigationOptions: {
headerShown: false
}
},
Client: {
screen: DrawerNavigator,
navigationOptions: {
headerShown: false,
},
},
StoreBooking: StoreBookingScreen,
StoreContract: StoreContractScreen,
IndexContracts: IndexContractsScreen,
ShowActivity: ShowActivityScreen,
ShowUniqueBooking: ShowUniqueBookingScreen,
Addresses: ShowAddressesScreen,
},
{
initialRouteName: init,
defaultNavigationOptions: {
headerStyle: {
backgroundColor: cli.Client.b1,
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}
})
RootNavigator = createAppContainer(AppNavigator);
return <RootNavigator />
}
return (
loaded && init ? (
<Awaiter />
)
:
returnRoute()
)
}

How to show props from reducers in component

I have a problem when want to show
const mapStateToProps = state => {
return {
loading: state.auth.loading,
error: state.auth.error,
userId: state.auth.userId,
tokenId: state.auth.token
}
}
this in my function
register = (event) => {
event.preventDefault()
this.props.onAuth( this.state.email, this.state.password, this.state.isSignup );
localStorage.setItem('token', this.props.tokenId);
localStorage.setItem('userId', this.props.userId);
}
I see token and userId after the second click. But I can't see after the first click. What I need more to show immediately?
This is my auth.js reducers
import * as actionTypes from '../actions/actionsTypes';
import { updateObject } from '../utility';
const initialState = {
token: null,
userId: null,
error: null,
loading: false
};
const authStart = ( state, action ) => {
return updateObject( state, { error: null, loading: true } );
};
const authSuccess = (state, action) => {
return updateObject( state, {
token: action.idToken,
userId: action.userId,
error: null,
loading: false
} );
};
const authFail = (state, action) => {
return updateObject( state, {
error: action.error,
loading: false
});
}
const reducer = ( state = initialState, action ) => {
switch ( action.type ) {
case actionTypes.AUTH_START: return authStart(state, action);
case actionTypes.AUTH_SUCCESS: return authSuccess(state, action);
case actionTypes.AUTH_FAIL: return authFail(state, action);
default:
return state;
}
};
export default reducer;
But, after the first click, I got token in my render function.
{this.props.tokenId}
Could you please help me? I think I need to use async/await. But I am not sure.
Here you go Header.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import * as actions from '../../store/actions/index'
import PropTypes from 'prop-types'
import './header.css'
class Header extends Component {
constructor(props) {
super(props)
this.state = {
email: '',
password: '',
isSignup: true,
token: false
}
this.handleChange = this.handleChange.bind(this);
}
handleChange (evt) {
this.setState({ [evt.target.name]: evt.target.value });
}
switchAuthModeHandler = (event) => {
event.preventDefault()
this.setState(prevState => {
return {
isSignup: !prevState.isSignup
}
})
}
register = (event) => {
event.preventDefault()
this.props.onAuth( this.state.email, this.state.password, this.state.isSignup );
localStorage.setItem('token', this.props.tokenId);
localStorage.setItem('userId', this.props.userId);
}
render() {
let regBtn = ''
if (this.state.isSignup) {
regBtn = 'Register'
}
else {
regBtn = 'Login'
}
let login = null
if(!this.props.tokenId) {
login = (
<div className="login">
<form onSubmit={this.register}>
<input type="email" placeholder="email" name="email" onChange={this.handleChange} />
<input type="password" placeholder="password" name="password" onChange={this.handleChange} />
<button>{regBtn}</button>
</form>
<div onClick={this.switchAuthModeHandler} className="switch">Switch to {this.state.isSignup ? 'Login' : 'Register'}</div>
</div>
)
}
else {
login = (
<div>
<p>Hello: {this.props.userId}</p>
<button>Logout</button>
</div>
)
}
if(this.props.loading) {
login = <div>Loading...</div>
}
return (
<div>
<div className="header-inner">
{this.props.tokenId}
{login}
<img src="http://civcic.com/assets/images/header-bg.jpg" alt="img" />
<div className="header-content">
<h2>React.JS DEVELOPER</h2>
<a className="knowmore-btn" href="https://www.upwork.com/freelancers/~01f507600be26cc2a3" rel="noopener noreferrer" target="_blank">Upwork profile</a><br />
<a className="knowmore-btn" href="https://www.linkedin.com/in/boris-civcic-37244378/" rel="noopener noreferrer" target="_blank">Linkedin</a><br />
<a className="knowmore-btn" href="https://github.com/fixman93" rel="noopener noreferrer" target="_blank">GitHub</a>
</div>
</div>
</div>
)
}
}
Header.defaultProps = {
tokenId: ''
}
Header.propTypes = {
tokenId: PropTypes.string
}
const mapStateToProps = state => {
return {
loading: state.auth.loading,
error: state.auth.error,
userId: state.auth.userId,
tokenId: state.auth.token
}
}
const mapDispatchToProps = dispatch => {
return {
onAuth: ( email, password, isSignup) => dispatch( actions.auth(email, password, isSignup))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Header)
import axios from 'axios';
import * as actionTypes from './actionsTypes';
export const authStart = () => {
return {
type: actionTypes.AUTH_START
}
}
export const authSuccess = (token, userId) => {
return {
type: actionTypes.AUTH_SUCCESS,
idToken: token,
userId: userId
}
}
export const authFail = (error) => {
return {
type: actionTypes.AUTH_FAIL,
error: error
};
};
export const auth = (email, password, isSignup) => {
return dispatch => {
dispatch(authStart());
const authData = {
email: email,
password: password,
fullName: 'Boris Civcic',
role: 'admin',
returnSecureToken: true
};
let url = 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=AIzaSyC5nW8-XOJADEvU7Mi7sgmhUNhHfRxXNQI';
if (!isSignup) {
url = 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=AIzaSyC5nW8-XOJADEvU7Mi7sgmhUNhHfRxXNQI';
}
axios.post(url, authData)
.then(response => {
console.log(response);
dispatch(authSuccess(response.data.idToken, response.data.localId));
// dispatch(checkAuthTime(response.data.expiresIn));
})
.catch(err => {
dispatch(authFail(err.response.data.error));
})
};
};
this is auth.js action
and this is utility
export const updateObject = (oldObject, updatedProperties) => {
return {
...oldObject,
...updatedProperties
};
};
In your register handler, onAuth is an asynchronous action but you've populated localStorage immediately. You should wait onAuth returns and then set your localStorage items.
first return a promise from your thunk ( simply by adding return before axios ):
...
return axios.post(url, authData)
.then(response => {
console.log(response);
dispatch(authSuccess(response.data.idToken, response.data.localId));
// dispatch(checkAuthTime(response.data.expiresIn));
})
.catch(err => {
dispatch(authFail(err.response.data.error));
})
...
Then set your localStorage items like this:
register = (event) => {
event.preventDefault();
this.props.onAuth( this.state.email, this.state.password, this.state.isSignup )
.then(() => {
localStorage.setItem('token', this.props.tokenId);
localStorage.setItem('userId', this.props.userId);
});
}

Ruby on Rails and React/Redux, Uncaught TypeError: (0 , _tasks.getTask) is not a function

I want to make a transition from a link to an article, to the article itself, when I click on a link, the construction is triggered: Not found. Tell me what I'm doing wrong.
task_conteiner.js
import React, { Component } from 'react';
import { browserHistory } from 'react-router';
import { Link } from 'react-router';
export default class TasksContainer extends Component {
onShowMoreTask(id) {
browserHistory.push(`#/tasks/${id}`);
location.reload()
}
renderTasks() {
let filterComleted = this.props.tasks.tasks
let str = '★'
let style
if (this.props.Completed === "task.completed") {
filterComleted = filterComleted.filter(task => task.completed);
} else {
filterComleted = filterComleted.filter(task => !task.completed);
}
return filterComleted.map((task) => {
if(task.completed){
style = {
textDecoration: 'line-through'
}
}
return (
<div key={task.id}>
<li className="todo">
<div className="container">
<div className="col-md-3" onClick={() => this.onShowMoreTask( task.id )}>{ task.title }</div>
<div className="col-md-3" style={style}>{ task.description }</div>
<div className="col-md-3" style={style}>{ task.due_date }</div>
<div className="col-md-1 star">{ str.repeat(task.priority) }</div>
<span onClick={() => this.props.onCompletedTask(task.id, task.completed)} className={task.completed ? "glyphicon glyphicon-repeat" : "glyphicon glyphicon-ok"} title={task.active ? "Mark active" : "Mark completed"}></span>
<span onClick={() => this.props.onEditTask( this.props.editId, task.id )} className="glyphicon glyphicon-pencil" title="Edit task"></span>
<span onClick={() => this.props.onDeleteTask(task.id)} className="glyphicon glyphicon-trash" title="Delete"></span>
</div>
</li>
</div>
);
});
}
render() {
return (
<div>
{this.renderTasks()}
</div>
);
}
}
task_details.js
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import Exit from '../authentication/exit';
import { browserHistory } from 'react-router';
import { getTask } from '../../actions/tasks';
import TasksList from './tasks_list';
import '../../index.css';
import Link from 'react-router'
class TaskDetails extends Component {
componentDidMount () {
let id = this.props.params.id;
this.props.onGetTask(id);
};
render() {
const { task } = this.props
console.log(this.props.location.pathname, "xxxxxxxx")
return (
<div>
{ this.props.task ?
<div className="container">
<h2 className="text-center">{task.title}</h2>
<div className="col-md-2">
<h4 className="pull-right"><i>{task.due_date}</i></h4>
</div>
<div className="clearfix"></div>
<div className="description">
<p>{task.description}</p>
</div>
</div>
:
<div className="container">
<div><h2>Not found</h2></div>
</div>
}
</div>
);
}
};
export default connect(
state => ({
task: state.tasks.item
}),
dispatch => ({
onGetTask: (id) => {
dispatch(getTask(id));
},
})
)(TaskDetails);
The task_details triggers the construction:
<div className="container">
<div><h2>Not found</h2></div>
</div>
There is an error in the console:
/tasks/6 xxxxxxxx
task_details.js:50 Uncaught TypeError: (0 , _tasks.getTask) is not a function
at Object.onGetTask (task_details.js:50)
at TaskDetails.componentDidMount (task_details.js:14)
at ReactCompositeComponent.js:265
at measureLifeCyclePerf (ReactCompositeComponent.js:75)
at ReactCompositeComponent.js:264
at CallbackQueue.notifyAll (CallbackQueue.js:76)
at ReactReconcileTransaction.close (ReactReconcileTransaction.js:80)
at ReactReconcileTransaction.closeAll (Transaction.js:206)
at ReactReconcileTransaction.perform (Transaction.js:153)
at batchedMountComponentIntoNode (ReactMount.js:126)
Thank you for your help.
and
reducers/task.js
export default function tasks(state = {
tasks: [],
edit: '',
sortBy: {title: "priority", asc: "desc"}
}, action) {
switch (action.type) {
case "FETCH_TODOS_SUCCESS":
return {
...state,
tasks: action.payload
};
case "GET_TASKS":
return {
...state,
tasks: action.payload
}
case "ADD_TASK":
return {
...state,
tasks: [action.payload, ...state.tasks]
}
case "DELETE_TASK":
state.tasks = state.tasks.filter(t => t.id !== action.payload);
return {
...state,
tasks: [...state.tasks]
}
case "EDIT_TASK":
state.tasks = state.tasks.filter(t => t.id !== action.payload.id);
return {
...state,
tasks: [action.payload, ...state.tasks]
}
case "COMPLITED_TASK":
state.tasks = state.tasks.filter(t => t.id !== action.payload.id);
return {
...state,
tasks: [action.payload, ...state.tasks]
};
case "EDIT_ID":
return {
...state,
edit: action.payload
}
case "SORT_BY":
return {
...state,
sortBy: action.payload
}
default:
return state;
}
}
action/task.js
import axios from 'axios';
import cookie from 'react-cookies';
//const API_URL = `https://evening-taiga-79121.herokuapp.com/todos`;
const API_URL = `http://localhost:3000/todos`;
let headers = { 'Content-Type': 'application/json', };
const token = cookie.load('token');
export function fetchTasks(user_id){
return function(dispatch, getState) {
let body = JSON.stringify({ token: token });
headers['Authorization'] = `Bearer ${token}`;
axios.get(`${API_URL}`, { headers, body })
.then(res => {
if (res.status === 200) {
dispatch({ type: 'GET_TASKS', payload: res.data });
}
})
.catch(e => {
console.error("error: ", e);
})
}
}
export function deleteTask(id){
return function(dispatch, getState) {
let body = { token: token };
axios.delete(`${API_URL}/${id}`, { params: body, headers: headers })
.then(res => {
dispatch({ type: 'DELETE_TASK', payload: id });
})
.catch(id => {
console.error("error", id);
})
}
}
export function addTask(task){
return function(dispatch, getState) {
let body = JSON.stringify({todo: task, token: token});
console.log(body);
axios.post(API_URL, body, { headers: headers })
.then(res => {
dispatch({ type: 'ADD_TASK', payload: res.data });
})
.catch(e => {
console.error(e);
})
}
}
export function completedTask(id, complete){
return function(dispatch, getState) {
if (complete === true) {
complete = false
} else {
complete = true
}
let task = {id: id, completed: complete};
let body = {todo: task, token: token};
axios.patch(`${API_URL}/${task.id}`, body, { headers: headers })
.then(res => {
dispatch({ type: 'COMPLITED_TASK', payload: res.data });
})
.catch(e => {
console.error("error: ", e);
})
}
}
export function sortTasks(sortBy){
return function(dispatch, getState) {
let body = JSON.stringify({ token: token, sortByTitle: sortBy.title, sortByAsc: sortBy.asc });
axios.post(`${API_URL}/sort`, body, { headers: headers })
.then(res => {
console.log(res);
if (res.status === 200) {
dispatch({ type: 'SORT_BY', payload: sortBy });
dispatch({ type: 'FETCH_TODOS_SUCCESS', payload: res.data });
}
})
.catch(e => {
console.error("error: ", e);
})
}
}
export function editTask(task){
return function(dispatch, getState) {
let body = JSON.stringify({todo: task, token: token});
axios.patch(`${API_URL}/${task.id}`, body, { headers: headers })
.then(res => {
dispatch({ type: 'EDIT_TASK', payload: res.data });
})
.catch(e => {
console.error("error: ", e);
})
}
}

Categories

Resources