How can I update my news feed after I add new post - mysql

I have a react frontend app with nodejs/express and typeorm/mysql on the backend. I have built a clone of twitter's "news feed" where we can post a new tweet(article). At the top, I have an input field where user can submit new post. Once the user submits new post, he has to refresh the page in order to be able to see new post. How can I achieve 'live reload' without reloading the app or seeing the new post once it is submitted. I am using useEffect() hook and fetch to send HTTP requests to communicate with backend.
Code for fetching posts and creating new one from the homepage:
const [posts, setPosts] = React.useState([]);
const [isLoaded, setIsLoaded] = React.useState(false);
const [error, setError] = React.useState(null);
const [post, setNewPost] = React.useState("");
React.useEffect(() => {
fetch(`${serverUrl()}/posts`)
.then((res) => res.json())
.then(
(posts) => {
setIsLoaded(true);
setPosts(posts);
},
(error) => {
setIsLoaded(true);
setError(error);
}
);
}, []);
const createNewPost = async (postData) => {
return fetch(`${serverUrl()}/posts`, {
method: "POST",
// add new
headers: { "Content-type": "application/json", userid: token },
body: JSON.stringify(postData),
}).then((data) => {
return data.json();
});
};
const handleSubmit = async (e) => {
e.preventDefault();
await createNewPost({ title: "Lorem ipsum", body: post });
setNewPost("");
};

In the createNewPost method, after the post has been added successfully, you must push the new post to your state.
const createNewPost = async (postData) => {
return fetch(`${serverUrl()}/posts`, {
method: "POST",
// add new
headers: { "Content-type": "application/json", userid: token },
body: JSON.stringify(postData),
}).then((data) => {
// success!
setPosts([...posts, postData]);
return data.json();
});
};
But of course, postData must match the schema of a single post inside your posts array for this to work.
The best solution for this is, to have the backend return the new post as JSON object, and then update the posts array.

A simple workaround would be that you could just manipulate the state of your "posts" variable.
In your createNewPost, if the promise returns in success without any errors or exceptions, i.e. enters into "then" block, you can append your new post -> {title: "new post", body: post} to the already fetched "posts" variable. This way state will be updated and you will see the new post.
i.e.
let prevPosts = [...posts];
prevPosts.push(newPost);
setPosts(prevPosts); // Append at last. You can even push at first index, that way post will appear at top.
So even if you refresh, the new posts will be loaded, as you already did a create query at backend while submitting the post and later updated the post variable.

Related

I need to fetch API to get a raw value from response same as the result in POSTMAN but fail?

I am new from here. Just stuck on some problem of fetching the data from frontend(react) to the raw value in JSON. For the login part, when I enter the email and password, supposedly the response are same as the result in POSTMAN, but i get the error. I am figure out this issue for almost oneweek. I would be appreciate for those who help me to solve on this issue. I will elaborate further on below about my situation:
Here is the response of API from postman (supposedly I should get this response):
The result I get in the browser:
Source Code:
constructor (props){
super(props);
this.state ={
loginEmail: '',
loginPassword: ''
}
this.login = this.login.bind(this);
this.onChange = this.onChange.bind(this);
}
login(){
PostData('api/users/login', this.state).then ((result) => {
let responseJSON = result;
console.log(responseJSON);
});
}
PostData:
export function PostData(type, userData = {}){
let BaseUrl = "https://ems-unimas-58134.herokuapp.com/"
return new Promise((resolve, reject) => {
fetch(BaseUrl+type,{
method: "POST",
body: JSON.stringify(userData),
Accept: 'application/json',
// headers:{
// 'Content-Type': 'application/json'
// }
}).then(res => res.json())
.then((responseJson) => {
resolve(responseJson);
})
.catch((error)=>{
console.error('Error:', error);
})
});
}
Commend down here if anyone of you need more code.
The problem is you need to allow CORS.
You can read more about CORS in here

keeps fetching the old json data?

I'm trying to fetch a json file from a https link however, no matter what link a give the result does not change!?
I validated all the json files. in case they had an error.
the responseData stays the same, and even when I force the data to change by instead returning responseData returning a json manually written; it changes right back to the old json data that just doesnt change when I return responseData back.
And the responseData that I requested to be be posted on the console gives the wrong information
The url given is correct.
but the output doesnt correspond to the data when I fill the link in the internetbrowser.
constructor(props){
super(props);
this.state = {
connected: false,
}
this.init = this.init.bind(this);
this.getJson = this.getJson.bind(this);
this.updateVisited = this.updateVisited.bind(this);
}
init = async ({json})=>{
if(json==null){
await AsyncStorage.setItem('database', "");
alert('error occured');
} else {
await AsyncStorage.setItem('database', JSON.stringify(json));
this.setState({
connected: true
});
}
}
getJson = async ()=>{
var url = await AsyncStorage.getItem("database_url");
console.log(url);
return fetch(url,
{
method: "GET",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
})
.then(response => response.json())
.then(responseData => {
this.updateVisited(url);
console.log(responseData);
return responseData;
})
.catch(error => {
alert('Could not connect!');
return null;
})
}
connect = async ({url})=>{
await AsyncStorage.setItem("database_url", url);
this.getJson().then(json => this.init({json}));
}
"a_json": [{"name": "greg"}]
"test": [{"name": "sheldon"}]
"temp": [{"name": "bob"}]
when the url points to the json test it gives bob expecting sheldon
when the url points to the json temp it gives bob expecting bob
when the url points to the json a_json it gives bob expecting greg
when returning a json without trying to fetch it from the internet at the place of responseData; it gives the expecting value
If you need more information, feel free to ask.
Thank you for your time reading my question.
The problem was the Cache-Control.
I added 'Cache-Control': 'no-cache' to the header of the fetch, which fixed the problem!
This was pointed out by #Pritish Vaidya in the comments

JSON response react native Post method problem

I am facing a strange problem, I am using Nexmo to verify number, and I am sending a post method
fetch('http://monasabat-app.com/basta_app/sign_up.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: formBody
}).then((response) => response.json())
.then((responseJson) => {
const ss1 = responseJson.status[0]
console.log(ss1)
let success = 'success'
if(ss1.status === success){
alert(ss1.status)
this.props.navigation.navigate('verNum',{
uid:ss1.uid,
phone:this.state.phone,
name:this.state.name,
emai:this.state.email
})
}else{
alert(ss1.status)
}
The sign up info(formBody) is successfully stored in the database but it doesn't navigate to the verNum screen neither alert the ss1.status but if the response is not success it does alert ss1.status in the else part (num is already registered) so I guess the problem is in the if condition part but the strange thing it does work sometimes and it doesn't some other times with a warning Possible Unhandled Promise Rejection (id: 1).
My JSON response
{
"status": [
{
"status": "success",
"uid": "99"
}
]
}
First, check if the this.props and this.state is accessible inside the promise.
If not before fetch create a variable that takes the value of this
Example let self = this;
then
this.props.navigation.navigate
would become
self.props.navigation.navigate.

laravel user api_token is undefined

i'm getting the 'unauthorized' error when trying to post a new comment with axios ..... i added (console.log(this.user.api_token);) just before axios.post in postComment() method . the output is : "undefined" !!!!!!!!!!
i'm learning and i don't know much about api's . but i don't think user api_token is to be set up manually .or does it ???
the script :
<script>
const app = new Vue({
el: '#app',
data: {
comments: {},
commentBox: '',
post: {!! $post->toJson() !!},
user: {!! Auth::check() ? Auth::user()->toJson() : 'null' !!}
},
mounted() {
this.getComments();
},
methods: {
getComments() {
axios.get('/api/post/'+this.post.id)
.then((response) => {
this.comments = response.data
})
.catch(function (error) {
console.log(error);
});
},
postComment() {
console.log(this.user.api_token);
axios.post('/api/post/'+this.post.id , {
api_token: this.user.api_token,
body: this.commentBox
})
.then((response) => {
this.comments.unshift(response.data);
this.commentBox = '';
})
.catch((error) => {
console.log(error);
})
}
}
})
api route
Route::get('/post/{post}', 'CommentController#index');
Route::middleware('auth:api')->group(function () {
Route::post('/post/{post}', 'CommentController#store');
});
CommentController
public function index(Post $post){
return response()->json($post->comments()->with('user')->get());
}
public function store(Request $req,Post $post){
$comment=$post->comment()->create([
'user_id'=>auth::id(),
'body'=>$req->body
]);
$comment=Comment::where('id',$comment->id)->with('user')->first();
return $comment->toJson;
}
If you are trying to consume your own api from vuejs there's no need to set the api token manually. Just update the web middleware group in app/Http/Kernel.php to include this line:
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class
This middleware will attach a laravel_token cookie that contains an encrypted JWT that Passport will use to authenticate API requests from your JavaScript application.
Read more here: https://laravel.com/docs/5.6/passport#personal-access-tokens
But, if you are consuming this same api from an external source like a mobile app, an api token will be required by passport to authenticate the request. The token can be created when the user is logged in or registered. Here's how:
//create a token
$token = $user->createToken('Token Name')->accessToken;
Then add an headers object to axios when making a request to the api
axios({
method: 'method',
url: 'url',
headers: {
'Accept' => 'application/json',
'Authorization' => 'Bearer '.$token
}
})
.then()
.catch()
Read more here: https://laravel.com/docs/5.6/passport#managing-personal-access-tokens

Aurelia typescript load json service

I am trying to create a class that will have two functions:
1) Load items from a json stored in my local server and return that variable with all the items.
2) Return a single item by id.
The problem is I want to use these two methods from different modules, and I do not know how to go about implementing the module and using it. So far, I have been able to implement the http part with aurelia's fetch client, but I don't know how to make the function:
function getItems() {
// some http request code
return fetchedItems;
}
Because the code in aurelia.io does something like this (which I have tried and actually works if I print the data):
import 'fetch';
import {HttpClient} from "aurelia-fetch-client";
export function getItems(url) {
let client = new HttpClient();
client.configure(config => {
config
.withBaseUrl('api/')
.withDefaults({
credentials: 'same-origin',
headers: {
'Accept': 'application/json',
'X-Requested-With': 'Fetch'
}
})
.withInterceptor({
request(request) {
console.log(`Requesting ${request.method} ${request.url}`);
return request;
},
response(response) {
console.log(`Received ${response.status} ${response.url}`);
return response;
}
});
});
client.fetch(url)
.then(response => response.json())
.then(data => {
console.log(data);
});
}
All this works ok. The point is that instead of doing 'console.log(data);' I want to return it, but so far the only thing that seems to work is assigning the returned items to a local class variable with 'this.items = data'. I would be ok with this so long as I get a function that allows to do this:
let items = getItems();
And
let item = getItemById(id);
EDIT: SOLVED
Users should note that, in order for this to work, they should have this in their tsconfig.js:
"target": "es6"
Because async/await requires at least ES2015.
Use async / await
If you're using TypeScript and targeting ES6, you can use the await/async keywords.
export async function getItems(url) {
let client = new HttpClient();
client.configure(config => {
config
.withBaseUrl('api/')
.withDefaults({
credentials: 'same-origin',
headers: {
'Accept': 'application/json',
'X-Requested-With': 'Fetch'
}
})
.withInterceptor({
request(request) {
console.log(`Requesting ${request.method} ${request.url}`);
return request;
},
response(response) {
console.log(`Received ${response.status} ${response.url}`);
return response;
}
});
});
return await client.fetch(url)
.then(response => response.json());
}
client.fetch returns a promise, so you just have to return it:
return client.fetch(url)
.then(response => response.json());
To use the function:
getItems(url)
.then(data => this.someProperty = data);