My pagination component is showing an extra, undesired item when the user is at or near either the beginning or the end of the item list. I believe I am matching my props exactly to what I am inputting in the documentation 'options' example, so I'm not sure where I'm going wrong.
Current behavior GIF
Desired behavior GIF
class MyPagination extends React.Component<PaginationProps> {
static defaultProps = {
boundaryRange: 0,
defaultActivePage: 1,
showEllipsis: false,
siblingRange: 2,
};
render() {
const {
boundaryRange,
defaultActivePage,
showEllipsis,
siblingRange,
totalPages,
} = this.props;
return (
<Pagination
boundaryRange={boundaryRange}
defaultActivePage={defaultActivePage}
ellipsisItem={showEllipsis ? undefined : null}
siblingRange={siblingRange}
totalPages={totalPages}
/>
);
}
}
export default MyPagination;
I'm instantiating like this:
<MyPagination totalPages={50} />
And my props are coming out as expected:
This issue is a bug and was fixed in semantic-ui-react#0.84.0 by https://github.com/Semantic-Org/Semantic-UI-React/pull/3271.
Related
I would like to add a 33% to the Wordpress Block "Button". So far it has 25%,50%,75% and 100%. Is it possible to insert my new value into the existing width selector?
I'm guessing Block Filters are the way to go.
I think I also found the way to get the settings object which might then help me to find out what I need to overwrite. However simply adding this code to my admin.js does not produce any output. Where would I need to load this?
const filterBlocks = (settings) => {
if (settings.name !== 'core/buttons') {
return settings
}
console.log(settings);
return settings;
}
Quick solution: Add a custom CSS class in the Buttons' block properties under "Advanced > Additional CSS class(es)" then define the custom width in your theme style.css
Detailed solution:
By using wp.hooks.addFilter() you can add a new control to the Button block with as many extra custom width options as you need. The Button blocks preset widths are defined within the function WidthPanel() of the blocks edit.js function:
function WidthPanel( { selectedWidth, setAttributes } ) {
...
return (
...
<ButtonGroup aria-label={ __( 'Button width' ) }>
{ [ 25, 50, 75, 100 ].map( ( widthValue ) => {
...
}
}
To add a new width value of 33% to the block, we need to add our own new button control to the InspectorControls and then use wp.hooks.addFilter() to add this to the existing core Button block, eg:
index.js
import { createHigherOrderComponent } from '#wordpress/compose';
import { Fragment } from '#wordpress/element';
import { InspectorControls } from '#wordpress/block-editor';
import { PanelBody, Button } from '#wordpress/components';
const withInspectorControls = createHigherOrderComponent((BlockEdit) => {
return (props) => {
const { setAttributes } = props;
let widthValue = 33; // must be a number
return (
<Fragment>
<BlockEdit {...props} />
<InspectorControls>
<PanelBody title="Custom Width">
<Button
key={widthValue}
isSmall
variant={widthValue}
onClick={() => setAttributes({ width: widthValue })}
>
{widthValue}%
</Button>
</PanelBody>
</InspectorControls>
</Fragment>
);
};
}, 'withInspectorControl');
wp.hooks.addFilter(
'editor.BlockEdit',
'core/button',
withInspectorControls
);
Next, a new additional css style needs to be added that (matches the existing width presets structure) for the new custom width, eg:
style.scss
$blocks-block__margin: 0.5em;
&.wp-block-button__width-33 {
width: calc(33.33% - #{ $blocks-block__margin });
}
And there you have it..
The easiest way to put all the code above together/working is to create your own Gutenberg block (and that in itself can be challenging if you aren't familiar with the process or ReactJS). I too have come across similiar challenges with Gutenberg, so I wanted to provide a detailed solution for this kind of issue that works.
I have following React code
Code
What I would like is to when I hover my "E-commerce" picture App component background should change on "E-commerce" picture background.
So respectively and for other pictures.
I will be very grateful if you help me solve this problem.
Context, according to the React docs, should be used only for truly global state like current user or theme. Using context for components makes them less reusable.
updated code
Your component tree is App -> SolutionBox -> SolutionItem.
You want to "react" to an event in SolutionItem in App but there is SolutionBox inbetween them so you have to thread the event thru SolutionBox to App.
Step 1
Add a prop to SolutionItem called on OnHover, this will be a function call back that any parent component can use to react to changes.
function SolutionsSectionBoxItem({ solutionIMG, onHover }) {
let callOnHover = state => {
if (_.isFunction(onHover)) {
onHover(state);
}
};
return (
<div className="solutions-section-item-box">
<img
src={solutionIMG}
alt=""
onMouseEnter={() => {
callOnHover(true);
}}
onMouseLeave={() => {
callOnHover(false);
}}
className="solutions-section-item-img"
/>
</div>
);
}
Step 2
Add a prop to SolutionBoxItem called on BGChanged, this will again be a function call back that will be called when any solutionitem onhover happens. This function will take a menuName string and pass either the current menu name or default.
function SolutionsSectionBox({ onBGChanged }) {
let callBGChanged = menuName => {
if (_.isFunction(onBGChanged)) {
onBGChanged(menuName);
}
};
return (
<div className="solutions-section-box-box">
<SolutionItem
solutionIMG={Ecommerce}
onHover={state => {
callBGChanged(state === true ? "Ecommerce" : "default");
}}
/>
<SolutionItem
solutionIMG={SalesMarketing}
onHover={state => {
callBGChanged(state === true ? "SalesMarketing" : "default");
}}
/>
<SolutionItem
solutionIMG={Analytics}
onHover={state => {
callBGChanged(state === true ? "Analytics" : "default");
}}
/>
<SolutionItem
solutionIMG={Middleware}
onHover={state => {
callBGChanged(state === true ? "Middleware" : "default");
}}
/>
</div>
);
}
Step 3
In the App component listen for the changes. In here we now set state when ever the mouse enters or leaves a solution item. From here you have to change the background, you are using css to control the background url, this will be harder since you now need css class for each background type. You could use the bgImage state value to change the name of the extra css className like 'AppSalesMarketing', 'AppEcommerce', etc.
export default function App() {
const [bgImage, setbgImage] = useState(E);
const onBGChanged = menuName => {
setbgImage(menuName);
};
return (
<div className={`App ${bgImage === "default" ? "" : `App${bgImage}`}`}>
<SolutionBox onBGChanged={onBGChanged} />
</div>
);
}
In CSS
Leave the original App class but based on the bgImage value add an additional one using the name of the bgImage + App like below to cascade down the updated background-image value.
.AppEcommerce {
background-image: url(https://placekitten.com/600/600);
}
.AppSalesMarketing {
background-image: url(https://placekitten.com/500/800);
}
.AppAnalytics {
background-image: url(https://placekitten.com/800/500);
}
.AppMiddleware {
background-image: url(https://placekitten.com/700/700);
}
Extra
I added lodash to test that the incoming props are functions before I call them, it is good to do defensive programming because you never know who may use your component in the future.
let callBGChanged = menuName => {
if (_.isFunction(onBGChanged)) {
onBGChanged(menuName);
}
};
Two ways to solve the problem. One is passing down a function to update state, the other is to useContext. In this case it makes sense to use context because you are passing down a function through multiple components that do not care about the function.
First thing to do is make the background image dynamic in the div's style and use context:
// Put this outside the component
export const BackgroundContext = React.createContext(null);
// -- snip
const [backgroundImage, setBackgroundImage] = useState(Ecommerce);
const updateBackgroundImage = newImage => setBackgroundImage(newImage);
// -- snip
<BackgroundContext.Provider value={updateBackgroundImage}>
<div className="App" style={{ backgroundImage: `url(${backgroundImage})` }}>
{/* -- snip */}
</BackgroundContext.Provider>
Now in your SolutionsSectionBoxItem component you can import the background context:
import BackgroundContext from "../App";
Then using that context and react's mouseover api, update the selected background image:
const setBackgroundImage = useContext(BackgroundContext);
// -- snip
<img onMouseOver={() => setBackgroundImage(solutionIMG)} {/* -- snip -- */} />
You can read more here: https://reactjs.org/docs/hooks-faq.html#how-to-avoid-passing-callbacks-down
my title question maybe duplicated but, I think its different :D..
I want to update array in firestore ... first time it work ,the second time will
give me this
warning: virtualizedlist: missing keys for items
and give me this error: collectionRferece.doc() required its first argument to be of not empty string but was undefined
I explained my code step by step.
Home.js
I receive data from firestore and i send it as a prop to projectList
render(){
const {projects,auth}=this.props;
return(
<ProjectList projects={projects} />
)
}
}
const mapStateToProps=(state)=>{
return{
projects:state.firestore.ordered.projects,
}
}
export default compose(connect(mapStateToProps),firestoreConnect([{collection:'projects',orderBy:['createdAt','desc']}])) (Feed);
ProjectList.js
there is just a flat list and sending data as a prop to projectsummery
const ProjectList =({projects})=> {
return(
<FlatList
data={projects}
refreshing={true}
renderItem={(project)=>{
return(
<ProjectSummery project={project} key={project.item.id}
keyExtractor={(item, index) => item.item.id}
/>
)
} }
/>
)
}
ProjectSummery.Js
there is some design and button, when i press the button i send project.item.id which is a (doc id) in firestore to project actions.js there is likePosts function which is update the array in firestore
import {likePosts} from '../Store/Actions/ProjectActions'
const ProjectSummery =(props)=> {
const {project,auth}=props
console.log(project.item.id);
return(
<>
<Container style={{flex:0,height:180}} >
<Content >
<Card>
<CardItem>
<Left>
<Button transparent onPress={()=>props.likePosts(project.item.id)}>
<Text>{project.item.likes.length} Likes</Text>
</Button>
</Left>
</Card>
</Content>
</Container>
</>
)
}
const mapDispatchToProps=(dispatch)=>{
return{
likePosts:(postId)=>dispatch(likePosts(postId))
}
}
export default connect(null,mapDispatchToProps)(ProjectSummery);
Actions.js
here i have likePosts fuction which update the array in firestore,
the fist time it works but the second time (project.item.id) postId will be undefined and i have no idea what's going on :D
export const likePosts =(postId)=>{
return (dispatch,getState,{getFirebase,getFirestore})=>{
const profile=getState().firebase.profile
const authId=getState().firebase.auth.uid
const firestore=getFirestore()
console.log(postId);
firestore.collection('projects').doc(postId).update({
likes:firestore.FieldValue.arrayUnion({
likedAt:new Date(),
likedBy: authId,
name: profile.firstName + profile.lastName
})
})
}}
Just in case anyone ends up on this question facing a similar issue, there is this SO question that appears to be different but the issue is caused by the same reason.
Check my answer there and the comments in under the question itself.
In addition to that, you can also check the Pagination section of this article for more guidance.
Original Answer:
What's happening is that when you click a like button the first time, it's working as expected so it gets the proper postId and then continues with the process you have defined. However, when you try the 2nd time it fails to fetch the postId as it's already liked.
The idea is that you'll need to either define an if statement and specify what should happen if it's already clicked and it get's clicked again (possibly storing the postId somewhere the first time and using it from there), or make an initial check that returns a specific message to the user if it's already clicked.
The issue has nothing to do with Firestore itself but with the button and the states of liked/unliked.
Here is one nice interactive example on codepen.io of a proper way of building like buttons using react. React Like Button
HTML
<div id="example"></div>
CSS
.btn-primary {
background-color: #23aa4e;
border-color: #177d37;
}
#example {
margin: 3rem;
}
.customContainer {
border: 1px solid black;
}
JS
class LikeButton extends React.Component {
constructor() {
super();
this.state = {
liked: false
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
liked: !this.state.liked
});
}
render() {
const text = this.state.liked ? 'liked' : 'haven\'t liked';
const label = this.state.liked ? 'Unlike' : 'Like'
return (
<div className="customContainer">
<button className="btn btn-primary" onClick={this.handleClick}>
{label}</button>
<p>
you {text} this. Click to toggle.
</p>
</div>
);
}
}
ReactDOM.render(
<LikeButton />,
document.getElementById('example')
)
I'm relatively new to React and working on a John Conway - Game of Life app. I have built a Gameboard.js functional component for the board itself (which is a child of App.js) and a Square.js functional component which represents an individual square in the board (and is a child of Gameboard and a grandchild of App).
In App I have a function called alive which I want to change the color of an individual square when it is clicked by the user. App also has an 'alive' property in it's state set to false initially and alive will change the property to true when called.
Here is App.js:
import React, { Component } from 'react';
import './App.css';
import GameBoard from './GameBoard.js';
import Controls from './Controls.js';
class App extends Component {
constructor(props){
super(props);
this.state = {
boardHeight: 50,
boardWidth: 30,
iterations: 10,
reset: false,
alive: false
};
}
selectBoardSize = (width, height) => {
this.setState({
boardHeight: height,
boardWidth: width
});
}
onReset = () => {
}
alive = () => {
this.setState({ alive: !this.state.alive });
console.log('Alive function has been called');
}
render() {
return (
<div className="container">
<h1>Conway's Game of Life</h1>
<GameBoard
height={this.state.boardHeight}
width={this.state.boardWidth}
alive={this.alive}
/>
<Controls
selectBoardSize={this.selectBoardSize}
iterations={this.state.iterations}
onReset={this.onReset}
/>
</div>
);
}
}
export default App;
Gameboard looks like this and passes props.alive to Square:
import React, { Component } from 'react';
import Square from './Square.js';
const GameBoard = (props) => {
return (
<div>
<table className="game-board">
<tbody>
{Array(props.height).fill(1).map((el, i) => {
return (
<tr key={i}>
{Array(props.width).fill(1).map((el, j) => {
return (
<Square key={j} alive={props.alive}/>
);
})}
</tr>
);
})}
</tbody>
</table>
</div>
);
}
export default GameBoard;
In my CSS I have a class called active that changes the color of an individual square if it is clicked on. How can I make it so that in Square if a td element is clicked the color changes (i.e. the CSS classes is changed to active)?
I've tried this:
import React, { Component } from 'react';
const Square = (props) => {
return(
<td className={props.alive ? "active" : "inactive"} onClick={() => props.alive()}></td>
);
}
export default Square;
The CSS looks like this:
.Square {
background-color: #013243; //#24252a;
height: 12px;
width: 12px;
border: .1px solid rgba(236, 236, 236, .5);
overflow: none;
&:hover {
background-color: #48dbfb; //#00e640; //#2ecc71; //#39FF14;
}
}
.inactive {
background-color: #013243; //#24252a;
}
.active {
background-color: #48dbfb;
}
How can I make it so the .Square CSS class is ALWAYS applied to every square but the individual square color is changed if it's active? In other words, can I set Square's td to always be styled with the .Square CSS class and then individual elements within Square can be colored appropriately depending on whether or not alive is true in App's state?
Is there are ternary approach to always set one particular CSS class and then, in addition, set 1 of 2 other classes....i.e. the Square CSS class is always shown and active or inactive is rendered depending on logic/state?
The comments have the right idea.
You could use a template literal and embed ternary conditionals in that:
return (
<td
className={`Square ${props.alive ? "active" : "inactive"}`}
onClick={() => props.alive()}
></td>
);
A quick refesher on template literals: use backticks to wrap a string, and you can insert a JavaScript expression inside of that by wrapping it in the ${} pattern. As a bonus, template literals can span multiple lines, so no more awkward string concatenation!
const myName = "Abraham Lincoln";
const myString = `Some text.
This text is on the next line but still in the literal.
Newlines are just fine.
Hello, my name is ${myName}.`;
Edit: The bigger problem that I see now is that you're not storing the state of each your cells anywhere. You have only a single boolean stored in App called alive... what you really need is an array of booleans, with each boolean representing the state of a single Square.
The array of "alive" states should live in the App or GameBoard, following the React principle of "the data flows down". In your case you could try keeping it in App, and that way GameBoard and Square can remain purely functional components.
Inside of App you could create a new 2-dimensional array, board, in the constructor and fill it with sub-arrays of 0 values initially:
// App.js
constructor(props){
super(props);
this.state = {
boardHeight: 50,
boardWidth: 30,
board: [],
iterations: 10,
reset: false,
};
this.state.board = new Array(this.state.boardHeight).fill(new Array(this.state.boardWidth).fill(0));
}
In the board array, each index represents one row. So a simplified example of [[0, 0, 1], [0, 1, 0], [1, 1, 1]] would represent:
0 0 1
0 1 0
1 1 1
GameBoard should render your grid of cells based purely on the board prop passed to it, and pass each Square its alive value and callback function as props:
const GameBoard = (props) => {
return (
<div>
<table className="game-board">
<tbody>
{this.props.board.map((row, y) => {
return <tr key={y}>
{row.map((ea, x) => {
return (
<Square
key={x}
x={x}
y={y}
isAlive={ea}
aliveCallback={this.props.alive}
/>
);
})}
</tr>;
})}
</tbody>
</table>
</div>
);
}
From there you should be able to see how this app would work. App stores the game state and renders the functional component GameBoard. In GameBoard, each Square renders according to its alive value, and triggers an aliveCallback when clicked. aliveCallback should set the state of the appropriate value in the board array inside of App, based on its x and y prop.
You can do like
return(
<td className={`Square ${props.alive ? "active" : "inactive"}`}
onClick={() => props.alive()}>
</td>
);
Please refer this code
Problem from title was not a real reason of 'not working'
NOTE: This statement
className={props.alive ? "active" : "inactive"}
is correct, using template literals isn't required.
You can write/use it in many ways:
className={'Square '+ (props.alive ? 'active' : 'inactive')}
To be true there is no need to use 'inactive' as 'Square' has the same bg color.
className={'Square '+ (props.alive ? 'active' : null)}
and de facto no need for ternary operator
className={'square '+ (props.alive && 'active')}
and of course you can 'calculate/prepare' values in plain js before return
const Square = (props) => {
let classes = ['Square','bb']
if( props.alive ) classes.push('active')
classes = classes.join(' ')
return (
<h1 className={classes}>Hello</h1>
)};
Just read docs or google for 'react css in js'.
I'm trying to put a react ag-grid into meteor, and i've hit what seems to be a css snag, but it's strange enough that i'm not sure and can't get past it.
If I don't include the ag-grid and ag-theme-fresh css files, my data comes in and appears -- all horribly unformatted, of course -- like this:
But if I include the two css files, I get what looks like a blank screen, except that everything is there, in grid form, as though all is well, but it's all invisible. Like this:
Here's my code -- can someone help me understand what's going on here?
class AdminThings extends Component {
constructor(props) {
super(props);
}
onGridReady( params ){
}
renderGrid(things) {
return (
<div className="ag-theme-fresh">
<AgGridReact
id="myGrid"
rowData={things}
onGridReady={this.onGridReady.bind(this)}
>
{Things.schema._schemaKeys.map((row, index) => {
return ( <AgGridColumn key={row} field={row}></AgGridColumn> );
})}
</AgGridReact>
</div>
);
}
render() {
return( !this.props.loading ? this.renderGrid(this.props.things) : <div></div>);
}
};
AdminThings.propTypes = {
loading: PropTypes.bool.isRequired,
things: PropTypes.array
};
export default AdminThings = withTracker(({ match }) => {
const subHandle = Meteor.subscribe( 'things' );
const loading = !subHandle.ready();
let things;
if ( !loading ) {
things = Things.find().fetch();
}
return {
loading,
things: things,
};
})(AdminThings);
I'm not familiar with total invisibility, except when something has opacity 0 on it, and that's not the case here. Thanks!
Figured it out from one of ag-grid's examples. By explicitly defining a height and width of the div that contains the AgGridReact component, everything miraculously appears. So, by changing the one line in the example above from this:
<div className="ag-theme-fresh">
to this:
<div style={{height: 400, width: 900, marginTop: 15}} className="ag-theme-fresh">
I get the desired result: