I am trying to replicate the search and masonry grid from the official documentation using their Codesandbox example.
However, when I am trying to use it, the code is not returning any gifs back.
I have verified that the JS fetch is indeed returning back gifs, it seems that the grid is not calling the fetchGifs function.
I am hitting the same issue with Carousel component as well.
Can anyone help me with this issue?
Codesandbox link for my implementation - https://codesandbox.io/s/cocky-waterfall-ny9rzk
Component i was trying to use - Search and Grid from https://github.com/Giphy/giphy-js/tree/master/packages/react-components
import { GiphyFetch } from "#giphy/js-fetch-api";
import { Grid } from "#giphy/react-components";
import useDebounce from "react-use/lib/useDebounce";
import React, { useState } from "react";
export default function App() {
const giphyFetch = new GiphyFetch("PZpYG85wQpugMlEx02GGqeKfKZ8eMdFZ");
const [debouncedInput, setDebouncedInput] = useState<string>("");
const [term, setTerm] = useState<string>("");
useDebounce(() => setTerm(debouncedInput), 500, [debouncedInput]);
const NoResults = <div className="no-results">No Results for {term}</div>;
const fetchGifs = (offset: number) => {
return giphyFetch.search(term, { offset, limit: 10 });
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<input
placeholder="type to search"
onChange={({ target: { value } }) => setDebouncedInput(value)}
value={debouncedInput}
/>
<Grid
key={term}
columns={3}
gutter={6}
noResultsMessage={NoResults}
width={400}
fetchGifs={fetchGifs}
/>
</div>
);
}
Try removing strict mode here:
https://codesandbox.io/s/cocky-waterfall-ny9rzk?file=/src/index.tsx
I guess the Grid is incompatible with React 18, possibly due to the useEffect change it brings.
Alternatively you could use React 17.x
Updated looks like they've introduced a fix
https://github.com/Giphy/giphy-js/commit/dade2aa10442c9ca8e6741125071dc1053e89181
Related
I was trying to use easy peasy for global state management within a nextjs app and was running into problems where the state would only update when I changed pages. I thought maybe I didn't quite grasp what I was doing so I decided to try a quick app with the quick start guide: https://easy-peasy.vercel.app/docs/tutorials/quick-start.html
Setting all this up nothing is happening when I click the button. If I make a change within the code and save it then all the changes happen when it hot reloads.
Does anyone have any idea why this is and how I fix it? I thought it might be nextjs but I just tested it with react and that's not working either. I must be missing some understanding of how this is supposed to work. In a tutorial I was following it worked just fine and cloning it also works. I have no idea when I try and create my own project with the same code its why it's not updating right away.
edit: I don't know why I didn't just share the repo. Here it is: https://github.com/Kyle-Kroger/easy-peasy-broken
edit 2: I tried to get Traversy Media's easy-peasy tutorial to work updating things for v5 and that does the same thing. Nothing updates when clicked but if I edit the code it will update the state on reload. I'm going to try on another computer in the morning.
https://github.com/Kyle-Kroger/traversy-media-easy-peasy-broken
edit 3: I think I might have figured it out. I wonder if it has something to do with version 18 of react. That is the only thing that is different between the repo I cloned that works and mine. Going to see how to use create-react-app with an older version and see if that will work.
edit 4: Well after many hours I figured out the problem. Something in react version 18 broke something with how easy-peasy works. Going back to 17 makes things work.
Here is all my code:
//store.js
import { createStore, action } from "easy-peasy";
export const store = createStore({
todos: [],
addTodo: action((state, payload) => {
state.todos.push({ text: payload, done: false });
}),
});
//body.js
import { useStoreState } from "easy-peasy";
const Body = () => {
const todos = useStoreState((state) => state.todos);
return (
<>
<p onClick={() => console.log(todos)}>Some more text to click</p>
<ul>
{todos.map((todo) => (
<li key={todo.text}>{todo.text}</li>
))}
</ul>
</>
);
};
export default Body;
//title.js
import { useStoreActions } from "easy-peasy";
import { useState } from "react";
const Title = () => {
const addTodo = useStoreActions((actions) => actions.addTodo);
const [value, setValue] = useState("");
return (
<>
<input onChange={(e) => setValue(e.target.value)} value={value} />
<button onClick={() => addTodo(value)}>Add Todo</button>
</>
);
};
export default Title;
_app.js
import "../styles/globals.css";
import { StoreProvider } from "easy-peasy";
import { store } from "../lib/store";
function MyApp({ Component, pageProps }) {
return (
<StoreProvider store={store}>
<Component {...pageProps} />
</StoreProvider>
);
}
export default MyApp;
//index.js
import Body from "../components/body";
import Title from "../components/title";
export default function Home() {
return (
<div>
<Title></Title>
<Body></Body>
</div>
);
}
Removing
<React.StrictMode></React.StrictMode>
from index.js fixes the issue on React 18.
Not a real solution but a workaround till Someone fixes it.
I was also having trouble with the update. Interestingly, I changed the StoreProvider from index.js to app.js and it works.
I am fairly new to react, so still getting my head around the component's lifecycle.
But the problem has left me scratching my head.
For instance, I do not understand why adding "setState(10);" causes style of the "Test" component to revert to it's default value yet the <div ref={ref2}>Hi</div> maintains it's style. (see imagebelow)
I am aware that "setState(10);" will cause a re-render but why is the style of the "Test" component being reverted?
Also, please ignore the "practical use" of calling setState(10) - I am aware it is pointless as it is never used, and I am aware that using "state" as a UseEffect dependency can solve this issue. But the main issue I have is understanding why the component's style reverts to it's default value.
import React, { useEffect, useState, useRef } from "react";
export default function App() {
const [state, setState] = useState();
let ref1 = useRef();
let ref2 = useRef();
useEffect(() => {
console.log("useEffect called ", ref1.current);
ref1.current.style.backgroundColor = "red";
ref2.current.style.backgroundColor = "green";
setState(10);
// }, [state]);
}, []);
const Test = React.forwardRef((props, ref1) => {
console.log("test called - rendering webpage", ref1.current);
return (
<div ref={ref1} {...props}>
HI from Test{" "}
</div>
);
});
return (
<div className="App">
<Test ref={ref1} />
<div ref={ref2}>Hi</div>
</div>
);
}
Console output
test called - rendering webpage undefined
useEffect called <div style="background-color: red;">HI </div>
test called - rendering webpage <div style="background-color: red;">HI </div>
The reason the style is disappearing is that you've defined your Test component inside your App component. That means that every time App renders, you'll define a new component type named Test. The text of that component is identical to the previous one, but it's a new type as far as react can tell, so react is forced to unmount the old one, and mount the new one. This wipes out any changes you made to the old one.
So at the very least, you need to move Test outside of App. That way, the component is just defined once, and will not remount on every render
export default App() {
// ...
}
const Test = React.forwardRef((props, ref1) => {
// ...
})
The above should fix the reset and let you experiment with refs, but i strongly recommend that you do not use refs to style your elements. Refs are an escape hatch that's sometimes needed, but the standard way to style a component is through the style prop. If you need to change the style, then you can have a state variable and let that control the style prop.
If you manually use javascript to set ref1.current.style.backgroundColor, react has no way to know that you did this, and so can't take those changes into account. In some circumstances, react may end up overwriting your changes, or may skip making changes that it doesn't realize it needs to do.
export default function App () {
const [colored, setColored] = useState(false);
useEffect(() => {
setColored(true);
}, [])
return (
<div className="App">
<Test style={colored ? { backgroundColor: "green" } : undefined} />
<div style={colored ? { backgroundColor: "red" } : undefined}>Hi</div>
</div>
);
}
// Don't really need forwardRef anymore, but i left it in
const Test = React.forwardRef((props, ref) => {
return (
<div ref={ref} {...props}>
HI from Test
</div>
);
});
import React, { useEffect, useState, useRef } from "react";
export default function App() {
const [state, setState] = useState();
let ref1 = useRef();
let ref2 = useRef();
useEffect(() => {
console.log("useEffect called ", ref1.current);
ref1.current.style.backgroundColor = "red";
ref2.current.style.backgroundColor = "green";
setState(10);
// }, [ref.current]);
}, [state]);
const Test = React.forwardRef((props, ref1) => {
console.log("test called - rendering webpage", ref1.current);
return (
<div ref={ref1} {...props}>
HI from Test{" "}
</div>
);
});
return (
<div className="App">
<Test ref={ref1} />
<div ref={ref2}>Hi</div>
</div>
);
}
The reason this is happening is once you update the state entire component gets rerendered. Your useEffect will run only once on componentDidMount hence the new ref that you get is not updated. To get rid of this you should use state as a dependency of the useEffect.
I've built a custom Input component which is simply a wrapper for the HTML input element. Here's the critical code, which I've simplified for posting here:
// #flow
import React, { useState } from 'react';
type Props = {
value?: string,
onChange: Function
};
const Input = ((props: Props) => {
const [ currentValue, setCurrentValue ] = useState(!!props.value ? props.value : '');
const handleChange = (event: SyntheticInputEvent<EventTarget>) => {
setCurrentValue(event.target.value);
props.onChange(event);
};
return <input type='text'
value={currentValue}
onChange={handleChange} />;
});
I wrote a bunch of React Testing Library tests for this and they all pass fine. But when I implemented this component in a web page, the initial value failed to appear. I solved the problem by dropping the currentValue code and just using props.value instead. That solves it. But I'm most curious why this approach above fails to display the initial value.
Look at this code, I did use prop-types
I'm doing a simple filter on my data using the Semantic UI React 'Input' Component. The data loads first, and then i apply the search filter to narrow down the data based on the user input.
It works, but when typing, it's very slow. I saw another user with a similar issue and someone mentioned onBlur but that doesn't seem to be working for me. Here is my Search component, which is passing a search state back to one of my other components which updates the data. Anyone have any recommendations here?
import React from "react";
import { connect } from "react-redux";
import { Input } from "semantic-ui-react";
import { searchChange, clearSearch } from "../reducers/searchReducer";
const Search = props => {
const handleSearch = event => {
props.searchChange(event.target.value.toLowerCase());
};
const style = {
marginBottom: 10
};
return (
<div style={style}>
<Input
icon="search"
placeholder="Enter filter..."
onChange={handleSearch}
/>
</div>
);
};
const mapStateToProps = state => {
return {
search: state.search,
filter: state.filter
};
};
export default connect(mapStateToProps, {
searchChange,
// filterChange,
clearSearch
})(Search);
I installed the rc-slider React Component on my React app, but I need to output the current values from the slider, how do I do that? This is the current code:
import React from 'react';
import 'rc-slider/assets/index.css';
import 'rc-tooltip/assets/bootstrap.css';
import Slider from 'rc-slider';
const createSliderWithTooltip = Slider.createSliderWithTooltip;
const Range = createSliderWithTooltip(Slider.Range);
export class RangeSlider extends React.Component {
render() {
return (
<div>
<Range min={0} max={10000} defaultValue={[800, 3000]} tipFormatter={value => `${value}€`} />
</div>
)
}
}
Also, how do I change the font-family from the tooltip where values are displayed when grabbing slider's handles?
You could store the slider values in state and use the onChange prop to update the slider values when they change.
The function given to tipFormatter can also return JSX as well as a string, so you can add a custom className and change font-family for that class.
Example
export class RangeSlider extends React.Component {
state = { sliderValues: [800, 3000] };
handleChange = sliderValues => {
this.setState({ sliderValues });
};
render() {
const { sliderValues } = this.state;
return (
<div>
{sliderValues[0]} - {sliderValues[1]}
<Range
min={0}
max={10000}
onChange={this.handleChange}
defaultValue={sliderValues}
tipFormatter={value => <span className="tooltip">{value}€</span>}
/>
</div>
);
}
}
For some reason, that last part of your code was not working for me as I was trying to get the range tooltip to animate correctly and display the correct data. I had to install an older version of rc-slider (8.7.1) in order to fix the tooltip animation that is currently broken at the time of this post. The code fix that got it all working correctly with the older version was:
...
tipFormatter={value => ${value}}
tipProps={{visible: true}}
...