Single React element child error - wrap statements inside a root component? - node.js

I'm seeing the error below with the second setState for the group.
Invariant Violation: React.Children.only expected to receive a single React element child
From reading it looks like I need to wrap these statements inside a root component or something similar; anyone help?
async componentDidMount() {
if (!this.props.isAuthenticated) {
return;
}
try {
const notes = await this.notes();
this.setState({ notes });
const group = await this.group();
this.setState({ group });
} catch (e) {
alert(e);
}
The full file can be found here - github.com/dodo83/giftlist/blob/master/Home.js

you need to return null, <></> or some kind of React component, e.g. <div>Foo</div>
Need to see your render function
I would also suggest you group the setState calls to a single call, e.g.
this.setState({ notes, group}); once the promises have resolved
Personally, i'd simplify your code to something more along these lines:
async componentDidMount() {
if (!this.props.isAuthenticated) {
return;
}
try {
const notes = await API.get("notes", "/notes");
const group = await API.get("group", "/group");
this.setState({ group , notes, isLoading: false});
} catch (e) {
}

Finally worked out what the issue was. I'd left a
*/}
in the middle of the renderGroup() method which is called by render() - (line 86)

Related

Error: Actions must be plain objects. Instead, the actual type was: 'string'

Error:
Actions must be plain objects. Instead, the actual type was: 'string'. You may need to add middleware to your store setup to handle dispatching other values, such as 'redux-thunk' to handle dispatching functions.
The below code is the client side where I dispatch the selected user id to actions.
const friendHandle = (e) => {
e.preventDefault()
setSwitch(false)
setFriend(!friend)
dispatch(friendUser(id))//id is the id from params of selected users
setFetchAgain(!fetchAgain)
}
useEffect(() => {
if(currentUser){
currentUser?.friends?.map(friends => {
console.log(friends._id)
console.log(currentProfile._id)
if(friends._id===currentProfile._id){
return setFriend(true)
}
})
}else{
return setFriend(false)
}
},[currentUser,currentProfile])
below is actions.js for the above code
export const friendUser = (id) => async (dispatch) => {
try {
await api.friendUser(id)
dispatch(id)
} catch (error) {
console.log(error)
}
}
I am trying to pass the id of the selected user but I am getting an error. I am new to React so I am not able to understand.
remove the dispatch(id) from the action, might be some copy\paste or merge error

Find document from mongoose collections with specific condition

Recently I start using MongoDB with Mongoose on Nodejs.
This code works as it should, and returns me all data i need :
const getAllPosts = async () => {
try {
return (await PostModel.find().populate('user')).reverse();
} catch (error) {
console.log(error);
throw Error('Error while getting all posts');
}
};
But now I only need individual posts, which in the tags (represented as an array in the PostModel) contain the data that I will pass in the request.
For example, I will make a GET request to /posts/tag111 and should get all posts that have "tag111" in the tags array.
Any ways to do this?
If you are using expressjs, your route should be something like:
whatever.get('/:tag', postController.getAllPostTagged)
The function you use in your route (called getAllPostTagged above) should be similar to this one, in which you get the path param tag from req:
const postController = {
getAllPostTagged = async(req, res) => {
try {
return (await PostModel.find({tags: req.params.tag}));
} catch (error) {
console.log(error);
throw Error('Error while getting all posts');
}
}
}
The key here is to know where the params are obtained (from req.params) .

React useState hook is running indefinitely - infinite loop

I have a simple react functional component.
The code should be self-explanatory. If the status is equal to 'some status', go to a URL, fetch some information, and set the state of the component to the information that has been fetched. On the return () just display the information. Everything works fine, the id of the data is displayed. However, when I open the dev tools and do the inspection, the console.log("data"+data.id); is run indefinitely. I wonder what is making it run indefinitely.
if I remove the change data(data) from inside the fetch, the console.log does not run indefinitely.
I am scratching my head as to why, changing the status would make the code enter in an infinite loop?
function ReturnInfo(props) {
var currentstatus = props.currentstatus; // receiving the current status as prop from parent.
const [data, changeData] = useState({});
let { slug } = useParams(); // getting the slug.
if (currentstatus == 'some status') {
fetch(`https:someurl/${slug}`).
then(res => res.json()).
then(data => {
console.log("data" + data.id);
changeData(data);
});
return (
<div>
<div>
{data.id}
</div>
</div>
)
}
else {
return (
<p>try harder!</p>
)
}
}
You should use useEffect, The Effect Hook lets you perform side effects in function components:
useEffect docs = https://reactjs.org/docs/hooks-effect.html
And if you don't add the dependency array it will run on each update.
Simple wrap your side-effect/async task code within the useEffect function.
And add the dependency array. add empty array if you want to run it only once.
useEffect(() => {
fetch(`https:someurl/${slug}`).
then(res => res.json()).
then(data => {
console.log("data" + data.id);
changeData(data);
});
}, [slug])
It will stop the unnecessary rerender.
Edit Try this
function ReturnInfo(props) {
var currentstatus = props.currentstatus; // receiving the current status as prop from parent.
const [data, changeData] = useState({});
let { slug } = useParams(); // getting the slug.
useEffect(() => {
fetch(`https:someurl/${slug}`).
then(res => res.json()).
then(data => {
console.log("data" + data.id);
changeData(data);
});
}, [slug])
if (currentstatus === 'some status') {
return (
<div>
<div>
{data.id}
</div>
</div>
)
}
return <p>try harder!</p>
}
You are calling the function every time the component is rendered. The function gets called, it updates the state, and makes the component to re-render.
You should call the function when an event occurrs or change the currentstatus value every time the block is executed.
changeData(data) will cause reevaluation of the component. Which leads to call fetch again, which make infinite loop.
useEffect(() {
if (currentstatus == 'some status') {
fetch(`https:someurl/${slug}`).
then(res => res.json()).
then(data => {
console.log("data" + data.id);
changeData(data);
});
}},[])

Express API returning an unwanted "data" section in my GET all requests

I'm currently building a rest API and I'm having an unexpected output when I make a /GET request.
When i make a get request to the API, it returns
{
data: {
[{myExpectedObjects},{myExpectedObjects}]
}
}
however, I'm expecting my get request to return just the array of objects. Below is the code im using to accomplish the rest calls
Create controller
const create = (req, res) => {
let dataModel = generateModel(genericDataFromReq);
dataModel = new dataModel({
genericData,
specificData,
});
dataModel.save().then((data) => {
res.status(201).send(data);
}, (e) => {
res.status(500).send(e);
});
}
};
get all controller
const list = (req, res) => {
const dataModel = generateModel(dataToGet);
dataModel.find().then((data) => {
if (data.length === 0) {
res.status(404).send('failed');
} else {
res.status(200).send({ data });
}
}, (e) => {
res.status(500).send(e);
});
};
generate data model
function generateModel(dbCollectionName) {
try {
return generateDataModel(dbCollectionName);
} catch (e) {
return mongoosee.model(`${dbCollectionName}`);
}
}
I know the code is a bit unconventional but I've set up a generic rest API to take in different types of requests and I found this solution to be the best way of doing this.
Any ideas on why my get all request is tacking on a "data" section before my array of objects (which is what I'm actually interest in)?
I believe the issue is in this line:
else {
res.status(200).send({ data });
}
When you put curly braces around a variable, it creates a key-value pair where the key is the name of the variable and the value is the value of the variable. So get rid of the curly braces and it should work as you expect. See the parts that mention this ES2015 notation here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer

Get response of action as a promise (like redux-thunk)

I am moving from redux-thunk to redux-saga but was finding one deficiency.
With redux-thunk I had a very typical way of doing "add requests":
try {
downloadId = await dispatch(requestDownload('SOME_URL'));
} catch(ex) {
console.log('download already existed, so request denied');
}
That action would return a promise, which I could wait on. The request function (requestDownload above) would either grant the request, and resolve with a downloadId or it would reject, if the download for that SOME_URL already existed.
How can I do this in redux-saga? It seems actions cannot return anything.
Thanks
In redux-saga you are not using await but yield in combination with effects instead.
Your code could look like this:
// saga.js
import { call, put } from 'redux-saga/effects'
import { requestDownloadSucceeded, requestDownloadFailed } from './reducer.js'
function* downloadRequestedFlow() {
try {
const downloadId = yield call(requestDownload, 'SOME_URL')
yield put(requestDownloadSucceeded(downloadId))
} catch(error) {
yield put(requestDownloadFailed(error))
}
}
// reducer.js
...
export const requestDownloadSucceeded = downloadId => ({
type: REQUEST_DOWNLOAD_SUCCEEDED,
downloadId,
})
export const requestDownloadFailed = error => ({
type: REQUEST_DOWNLOAD_FAILED,
error,
})
Note the generator function with a * that allows the usage of yield. I'm also using the common REQUESTED, SUCCEEDED, FAILED pattern here.
I hope this answer was helpful.

Resources