React.Children.only expected to receive a single React element child. But only single children in files? - react-bootstrap

All my other pages work fine. And this happened after I made an addition to App.js, which I subsequently removed. Obviously I must have made some other change, I'm not able to find it however.
Error: React.Children.only expected to receive a single React element child.
▶ 18 stack frames were collapsed.
(anonymous function)
src/components/Feed.js:16
13 | .then(res => res.json())
14 | .then((data) => {
15 |
> 16 | this.setState({ events: data })
| ^ 17 |
18 | })
19 | .catch(console.log)
Looking at Feed.js I've not modified anything here.
import React, {Component} from "react";
import Header from "./Header"
import Events from "./Events"
class Feed extends Component {
state = {
events: []
}
componentDidMount() {
fetch('http://127.0.0.1:5002/events')
.then(res => res.json())
.then((data) => {
this.setState({ events: data })
})
.catch(console.log)
}
render() {
return (
<div className="feed">
<Header />
<div class="container">
<Events events={this.state.events} />
</div>
</div>
);
}
}
export default Feed;
And the only other component it calls is as below:
import React from 'react';
import Accordion from 'react-bootstrap/Accordion'
import Card from 'react-bootstrap/Card'
import Alert from 'react-bootstrap/Alert'
import Button from 'react-bootstrap/Button'
import './App.css'
function Events ({events}){
return (
<div>
<center><h1>Event List</h1></center>
{events.map((event) => (
<div class="mt-2">
<Accordion defaultActiveKey="0" className="rounded ">
<Card className="rounded">
<Accordion.Toggle as={Alert} variant="secondary" eventKey={event.id} className="accordion-title border-0"><span className="badge badge-secondary">{event.date}</span><span> </span><span>{event.title}</span>
</Accordion.Toggle>
<Accordion.Collapse eventKey={event.id} className="accordion-collapse">
<Button href="detail" variant="secondary" size="lg" disabled>Link</Button>
<Card.Body className="rounded">{event.summary}</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
</div>
))}
</div>
)
}
export default Events;
As I said I've not modified anything in these two files and I've made sure to remove any changes to other files.

I did make a change which caused the issue.
In Events.js I added a new button to the accordion. On removing this everything worked fine.
The offending entry
<Button href="detail" variant="secondary" size="lg" disabled>Link</Button>
The Button should have been inside the Card.Body.
<Accordion defaultActiveKey="0" className="rounded ">
<Card className="rounded">
<Accordion.Toggle as={Alert} variant="secondary" eventKey={event.id} className="accordion-title border-0"><span className="badge badge-secondary">{event.date}</span><span> </span><span>{event.title}</span>
</Accordion.Toggle>
<Accordion.Collapse eventKey={event.id} className="accordion-collapse">
<Card.Body className="rounded">{event.summary}
<Button href="detail" variant="secondary" size="lg" disabled>Link</Button>
</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>```

Related

Alpinejs x-if is not being triggered

I have data that I am pulling from ajax. And I want this data display only when it is successfully pulled.
import Alpine from 'alpinejs'
import axios from 'axios'
const http = axios.create({
baseURL: 'url',
})
window.axios = http
window.Alpine = Alpine
document.addEventListener('alpine:init', () => {
Alpine.data('cart', () => ({
items: null,
init(){
window.axios.get('wc/store/cart')
.then(({data})=>{
this.items = data
console.log(this.items)
}).catch(error => {
console.log(error.toString())
})
},
}))
})
Alpine.start()
Now I am using this in my template
<div x-data="cart">
<template x-if="items">
<h1>Shopping Cart</h1>
<!-- display items here -->
</template
</div>
The thing is, the h1 element is displayed but not the data from ajax.
Am I doing anything wrong. I am pretty confidence this should work.
You're not displaying your items. Keep in mind that template tags require a single root element only.
<div x-data="card">
<template x-if="items">
<div>
<h1>Shopping Cart</h1>
<template x-for="item in items">
<div>
<h2 x-text="item.text"></h2>
</div>
</template>
</div>
</template>
</div>

Update state of an object using useState not working

Hi I´m doing a tutorial from 1 year ago and seems it is already obsolet.
I´m using folowing versions:
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-scripts": "5.0.1",
the lines: setNames([...names, { id: names.length, name }])
seems not working well, cause it is still empty after using it.
import React, { useState } from "react";
import './App.css';
function App() {
const [name, setName] = useState("");
const [names, setNames] = useState([]);
function addNames(e) {
e.preventDefault();
setNames([...names, { id: names.length, name }]);
}
return (
<div className="App">
<form onSubmit={addNames}>
<input
type="text"
value={name}
placeholder="add names"
onChange={(e) => setNames(e.target.value)}
/>
<button>Submit</button>
</form>
<ul>
//{names.map((item) => (
// <li key={item.id}>{item.name}</li>
// obsolet, solution:
{Object.keys(names).map((item) => (
<li key={names}>{names[item}]</li>
))}
</ul>
</div>
);
}
export default App;
You created function addNames that seems to be right and you're not using it in <input> event onChange
Can you call addNamesin onChange and tell me what happens?

Add parameter at onClose in relation Modal

Goal:
When you press the button named "yes 1", the value should contain "yes yes" and in the end the console.log should display "test yes yes".
When you press the button named "yes 2", the value should contain "no no" and in the end the console.log should display "test no no".
The display of the value "test yes yes" or "test no no" take place at index.tsx.
The execution or the decision take place at ModalForm.tsx.
Problem:
In technical perspectiv, tried to find a solution by using this code onClick={props.onClose("yes yes")} but it doesn't work.
How do I solve this case?
Stackblitz:
https://stackblitz.com/edit/react-ts-rpltpq
Thank you!
index.html
<div id="root"></div>
<!-- Latest compiled and minified CSS -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<!-- Latest compiled JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js"></script>
index.tsx
import React, { Component, useState, useEffect } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import { ModalForm } from './ModalForm';
import './style.css';
interface dddd {
clientid: string | undefined;
idid: number;
}
const getTest = () => {
console.log('test');
};
const App = () => {
const [clientiddd, setClientid] = useState('ddfdf');
const [idid, setIdid] = useState(0);
return (
<div>
<button
data-bs-toggle="modal"
data-bs-target="#myModalll"
className={'btn btn-outline-dark'}
>
{'data'}
</button>
<br />
<ModalForm clientid={clientiddd} onClose={getTest} />
</div>
);
};
render(<App />, document.getElementById('root'));
ModalForm.tsx
import React, { Component } from 'react';
interface ModalProps {
clientid: string | undefined;
onClose: () => void;
}
export const ModalForm = (props: ModalProps) => {
return (
<div
className="modal"
id="myModalll"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h4 className="modal-title">T</h4>
<button
type="button"
className="btn-close btn-close-black"
data-bs-dismiss="modal"
onClick={props.onClose}
></button>
</div>
<div className="modal-body">
TITLE:
<br />
<button
type="button"
data-bs-dismiss="modal"
onClick={props.onClose}
>
yes 1
</button>
<button
type="button"
data-bs-dismiss="modal"
onClick={props.onClose}
>
yes 2
</button>
<br />
</div>
</div>
</div>
</div>
);
};
It's somewhat hard to understand your question, but let me try.
onClick={props.onClose('yes yes')}
What this code does is that it calls props.onClick with yes yes as an argument and assigns the returned value as the onClick listener.
Assume the props.onClose is this:
function onClose() {
console.log('test')
}
What it does here is that it calls this function (it logs test to the console) but since this function is not returning anything, it passes undefined as the onClick here.
If instead your function was this:
function onClose(result) {
return function () {
console.log('test', result)
}
}
Now it would call props.onClose with yes yes and it would return a function. This anonymous function would be passed as the onClick event listener and when you click, it would call that so there would be test yes yes logged only after clicking.
You can as well do it differently, keep your onClose function as it was but introduce result:
function onClose(result) {
console.log('test', result)
}
but now you have to pass this function instead of calling it:
onClick={() => props.onClose('yes yes')}
As you can see, there will always be one anonymous function somewhere in there, it's just a question of where that function is and what is called when. Hope this explanation helps.
https://stackblitz.com/edit/react-ts-nw6upt?file=index.html
index.html
<div id="root"></div>
<!-- Latest compiled and minified CSS -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<!-- Latest compiled JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js"></script>
index.tsx
import React, { Component, useState, useEffect } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
import { ModalForm } from './ModalForm';
interface dddd {
clientid: string | undefined;
idid: number;
}
const getTest = (result: string) => {
console.log('testff ' + result);
};
const App = () => {
const [clientiddd, setClientid] = useState('ddfdf');
const [idid, setIdid] = useState(0);
return (
<div>
<button
data-bs-toggle="modal"
data-bs-target="#myModalll"
className={'btn btn-outline-dark'}
>
{'data'}
</button>
<br />
<ModalForm clientid={clientiddd} onClose={getTest} />
</div>
);
};
render(<App />, document.getElementById('root'));
ModalForm.tsx
import React, { Component } from 'react';
interface ModalProps {
clientid: string | undefined;
onClose: (result: string) => void;
}
export const ModalForm = (props: ModalProps) => {
return (
<div
className="modal"
id="myModalll"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-labelledby="staticBackdropLabel"
aria-hidden="true"
>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h4 className="modal-title">T</h4>
<button
type="button"
className="btn-close btn-close-black"
data-bs-dismiss="modal"
onClick={() => props.onClose('ccc')}
></button>
</div>
<div className="modal-body">
TITLE:
<br />
<button
type="button"
data-bs-dismiss="modal"
onClick={() => props.onClose('aaa')}
>
yes 1
</button>
<button
type="button"
data-bs-dismiss="modal"
onClick={() => props.onClose('bbb')}
>
yes 2
</button>
<br />
</div>
</div>
</div>
</div>
);
};

Using Refs in a Dynamic Length Array for scrollIntoView

I am somewhat new to using useEffect and useRef. What I'm trying to do is create a content management system that enables scrollIntoView for n number of page elements from a database for a single page scrolling app.
I'm not able to get it to work so I'm hoping for some assistance.
I've posted a simple test where I have a functional react component where section 2 works (clicking the button scrolls down to the page element.
But my goal is to take 'n' sections from a database and create 'n' number of refs to scroll down to 'n' number of sections.
I tries useRef, useEffect, etc but I'm stumped. My code snippet shows a working example with manual ref declarations for Section 2 but Section 1 attempts to use a collection of Refs and that's not working
Here is a code example: https://codesandbox.io/embed/trusting-stallman-bsjj1?fontsize=14
import React, { useRef } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const App = () => {
let pageRef = useRef([
React.createRef(),
React.createRef()
]);
const pageHomeRef = React.createRef();
const scrollToRef = ref => ref.current.scrollIntoView({ behavior: "smooth" });
const scrollToPane = ref => scrollToRef(ref);
return (
<div className="App">
<div className="menu">
<button
onClick={() => {
scrollToPane(pageRef[1]);
}}
>
Scroll to Section 1
</button>
<button onClick={() => scrollToPane(pageHomeRef)}>
Section 2
</button>
</div>
<div className="page" style={{ marginTop: "1500px", marginBottom: "1500px" }}>
<div className="section1" ref={pageRef[1]}>
Section 1
</div>
<div className="section2" ref={pageHomeRef}>
Section 2
</div>
</div>
</div>
);
};
I'd like to feed an array of page elements and have the refs dynamically change as needed.
Little order the code - try it
You can use React.createRef() or useRef(null) in the array.
And make us many refs you want in array.
And even make map if you have a list (https://dev.to/ajsharp/-an-array-of-react-refs-pnf)
And you have other ways insted of refs.
import React, { useRef } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const App = () => {
let pageRef = [useRef(null),useRef(null)];
const pageHomeRef = [React.createRef(),React.createRef()];
const scrollToRef = ref => ref.current.scrollIntoView({ behavior: "smooth" });
const scrollToPane = num => scrollToRef(pageRef[num]);
return (
<div className="App">
<div className="menu">
<button
onClick={() => {scrollToPane(0)}}>Scroll to Section 1</button>
<button onClick={() => scrollToPane(1)}>Section 2</button>
</div>
<div
className="page"
style={{ marginTop: "1500px", marginBottom: "1500px" }}
>
<div className="section1" ref={pageRef[0]}>
Section 1
</div>
<div className="section2" ref={pageRef[1]}>
Section 2
</div>
</div>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

merge values from pluck and combineLatest inside map rxjs

I've a prop of addHandler passed to AddTodo component from App.js. Then inside AddTodo handler I'm not sure how do I combine pluck and map so that I've value from pluck as well as combineLatest merged inside map
Here's my code
App.js
import React from 'react';
import { componentFromStream , createEventHandler } from "recompose";
import { combineLatest } from "rxjs";
import { map, tap } from "rxjs/operators";
import AddTodo from './AddTodo/AddTodo';
import Todos from './Todos/todos';
// import User from './User/User';
const App = componentFromStream(prop$ => {
const { handler: onAddHandler, stream: clickStream } = createEventHandler();
const value$ = clickStream.pipe( tap(input =>
console.warn(input)
));
return combineLatest(prop$, value$).pipe(map(([props, value]) => <div>
<AddTodo onAddHandler={onAddHandler} />
{/* <input placeholder="Add TODO" onChange={handler} /> */}
<Todos todo={value} />
</div>));
});
export default App;
AddTodo.js
import React from "react";
import { combineLatest } from "rxjs";
import { componentFromStream, createEventHandler } from "recompose";
import { pluck, map, startWith, tap } from "rxjs/operators";
const AddTodo = componentFromStream(prop$ => {
const {
handler: onChangeHandler,
stream: inputStream
} = createEventHandler();
const value$ = inputStream.pipe(
map(e => e.target.value),
startWith("")
);
return combineLatest(prop$, value$).pipe(
map(([props, value]) => (
<div>
<input
type="text"
placeholder="Add Todo..."
onChange={onChangeHandler}
/>
<button onClick={() => {}}>Add todo</button>
{/* <button onClick={() => onAddHandler(value)}>Add todo</button> */}
</div>
))
);
});
export default AddTodo;
Inside AddTodo.js inside map I probably I'm looking for something like
return combineLatest(prop$, value$).pipe(
pluck('onAddHandler'),
// and use this value plus the belo values inside map
map(([props, value]) => (
all your need to do is move pluck inside combineLatest which look like this, then you
should get the onAddHandler in the map operator:
return combineLatest(prop$.pipe(pluck('onAddHandler')), value$).pipe(
map(([onAddHandler, value]) => (
<div>
<input
type="text"
placeholder="Add Todo..."
onChange={onChangeHandler}
/>
<button onClick={() => {}}>Add todo</button>
{/* <button onClick={() => onAddHandler(value)}>Add todo</button> */}
</div>
))
);

Resources