Detecting scroll direction using hooks - scroll

Here is my code:
const [scollPosition, setSrollPosition] = useState(0);
const handleScroll = () => {
const position = window.pageYOffset;
console.log(position);
if (position > scollPosition) {
console.log("down");
} else {
console.log("up");
}
setSrollPosition(position);
};
useEffect(() => {
window.addEventListener("scroll", handleScroll, { passive: true });
return () => window.removeEventListener("scroll", handleScroll);
}, []);
But it doesn't work, because setSrollPosition(position) didn't update the value of scollPositon.

It's the nature of Reactjs's state, it's updated asynchronously
For your case, use useRef() instead, so you won't need to care about the thing above:
const scollPosition = useRef(0);
const handleScroll = () => {
const position = window.pageYOffset;
console.log(position);
if (position > scollPosition.current) {
console.log("down");
} else {
console.log("up");
}
scollPosition.current = position;
};
useEffect(() => {
window.addEventListener("scroll", handleScroll, { passive: true });
return () => window.removeEventListener("scroll", handleScroll);
}, []);
Working example:
function App() {
const scollPosition = React.useRef(0);
const handleScroll = () => {
const position = window.pageYOffset;
console.log(position);
if (position > scollPosition.current) {
console.log("down");
} else {
console.log("up");
}
scollPosition.current = position;
};
React.useEffect(() => {
window.addEventListener("scroll", handleScroll, { passive: true });
return () => window.removeEventListener("scroll", handleScroll);
}, []);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div>
<div id="root"></div>

Related

Vue js in laravel [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I'll post the code, I can't store the data in the tweets array, where am I wrong? i am using vue and laravel
<script>
export default {
mounted() {
this.recupera_post()
},
data(){
return{
tweets:[]
}
},
methods:{
async recupera_post(){
await axios.get('api/schedulepost')
.then(function(response){
console.log(response.data)
app.tweets=response.data
})
}
}
}
</script>
you just need to write this.tweets also you need to change your callback function to arrow function to allow you to access your state like this
async recupera_post(){
await axios.get('api/schedulepost')
.then((response) => {
console.log(response.data)
this.tweets = response.data
})
}
}

CKEditor5 insert non-editable text in the editor

I am trying to insert small pieces of text in the CKEditor5, like
{{ variable name }}
These variables shall not be edited by user. I tried to insert
content = '<span contenteditable="false">' + content + '</span>';
Using the following code, content is the non-editable string
content = '<span contenteditable="false">' + content + '</span>';
const viewFragment = this.editor.data.processor.toView( content );
const modelFragment = this.editor.data.toModel( viewFragment );
this.editor.model.insertContent( modelFragment );
It does not work. The wrapping part is always removed by CKEditor. What should I do to achieve this?
you should configure editor to allow for other tags
and you need html Editing plugin (sorry I forgot the real name of it)
public config = {
placeholder: 'content here',
htmlSupport: {
allow: [
{
name: /.*/,
attributes: true,
classes: true,
styles: true
}
]
}
}

How to implement custom dropdown toggle state with react bootstrap dropdown

I am trying to implement a custom toggle for a react dropdown that has a chevron up and down on the arrow.
I tried moving the toggle inside the LocaleSwitcher function and use the state from that component, but it causes some type of error where the document gets unbound from the component after updating the state once, the next click it breaks.
I'm not familiar with the forward referencing, the code was mostly copy paste from a google article, so I'm not 100% sure how it's working.
My question is, in the code below - is there a way to detect and update the state to switch the up/down arrow?
{**how to toggle a condition to show/hide based on dropdown state? ** ? upArrow : downArrow}
import styles from "./LocaleSwitcher.module.scss";
import Dropdown from "react-bootstrap/Dropdown";
import React, {useState} from 'react';
// found this code on Google.
const downArrow = (
<span>▲</span>
)
const upArrow = (
<span>▼</span>
)
const CustomToggle = React.forwardRef(({ children, onClick }, ref) => (
<a
href=""
ref={ref}
onClick={(e) => {
e.preventDefault();
onClick(e);
}}
>
{children}
{true ? upArrow : downArrow}
</a>
));
const LocaleSwitcher = (props) => {
const data = [
{label: "Australia (AU$)", currency: 'AUD', locale: 'en_AU', link: 'https://www.rmwilliams.com.au'},
{label: "Canada (CAD$)", currency: 'CAD', locale: 'en_CA', link: 'https://www.rmwilliams.com'},
{label: "Denmark (kr.)", currency: 'Kr.', locale: 'en_AU', link: 'https://www.rmwilliams.com.au'}
];
const [locale, setLocale ] = useState(data[0]);
const [show, setShow] = useState(false);
const onToggle = (args) => {
console.log(JSON.stringify(args, null, 2));
setShow(args);
}
const onSelect = (args) => {
const locale = data.find((item) => item.label === args);
console.log(JSON.stringify(args, null, 2));
console.log('found ' + JSON.stringify(locale));
setLocale(locale);
}
return (
<div className={styles.locale_switcher}>
<Dropdown onToggle={onToggle} onSelect={onSelect}>
<Dropdown.Toggle as={CustomToggle} variant="success" id="dropdown-basic">
{locale.label}
</Dropdown.Toggle>
<Dropdown.Menu>
{data.map((locale) => <Dropdown.Item key={locale.label} eventKey={locale.label}>{locale.label}</Dropdown.Item>)}
</Dropdown.Menu>
</Dropdown>
</div>
);
};
export default LocaleSwitcher;

Export componenent after ajax call finishes in React

I want to export a component after the ajax call finishes. Here is the below code, the output of below code is
exporting 1
exporting 3
exporting 4
exporting 2
But I want to execute it sequentially, My desired output is
exporting 1
exporting 2
exporting 3
exporting 4
import appLocaleData from "react-intl/locale-data/en";
import enMessages from "../locales/en_US.json";
import config from "config";
const lang = new Object();
console.log( " exporting 1" );
fetch(`${config.api.languageUrl}english.json`, {
method: "GET",
headers: {
"Content-Type": "application/octet-stream"
}
})
.then(res => res.json())
.then(json => {
Object.assign(lang, json);
console.log("json->", json);
console.log("lang->", lang);
console.log(lang._VIEW);
console.log( "exporting 2" );
});
console.log( "exporting 3" );
const EnLang = {
messages: {
...lang
},
locale: "en-US",
data: appLocaleData
};
console.log( "exporting 4" );
export default EnLang;
Is there anyway in react, I can perform this ?
Thanks,
No, there is no such thing as an asynchronous export in javascript. If you can be more clear about what you are trying to accomplish I might be able to suggest a possible approach, but as is I don't even understand how this has anything to do with React specifically
EDIT based on OP's reply:
try something like this...
export const LocalsContext = React.createContext([]);
const App = () => {
...
const [locals, setLocals] = useState([]);
useEffect(() => {
fetch(...)
.then(...)
.then(localsList => setLocals(localsList)
}, []);
return (
<LocalsContext.Provider value={locals}>
...
</LocalsContext.Provider>
)
}
export default App
and then in any component anywhere within your app you can access the locals like so:
const MyComponent = () => {
/*
* will re-render whenever the locals updates,
* i.e., will render once with [] as the value, then once the
* data is fetched it will render again with the actual locals value
*/
const locals = useContext(LocalsContext);
return <div>some component</div>
}

Refresh preloaded data with Sapper

I am currently learning Sapper and integrating it with a GraphQL service.
To start with an easy spot, I made a FAQ page with a simple list of question/answer plus a creation form.
<script context="module">
import graphql from '../graphql';
import gql from 'graphql-tag';
export function preload({ params, query }) {
const graphQuery = gql`
{
faqEntries {
question,
answer
}
}
`;
return graphql.request(graphQuery).then((data) => data);
}
</script>
<script>
import title from './title';
import Input from '../components/form/Input';
import Button from '../components/Button';
export let faqEntries;
const newEntry = {
question: '',
answer: '',
};
const addEntry = () => {
console.log(newEntry);
graphql.request(gql`
mutation {
createFaqEntry(
question: "${newEntry.question}"
answer: "${newEntry.answer}"
) {
id
question
answer
}
}
`).then((data) => {
console.log(data);
newEntry.question = '';
newEntry.answer = '';
})
}
</script>
<svelte:head>
<title>{title('Foire aux questions')}</title>
</svelte:head>
<section class="container">
<h1>Foire aux questions</h1>
<form on:submit|preventDefault>
<Input id="question" label="Question" bind:value={newEntry.question} />
<Input id="answer" label="Réponse" bind:value={newEntry.answer} />
<Button on:click={addEntry} >Ajouter une entrée</Button>
</form>
{#each faqEntries as faqEntry}
<div class="py-4">
<h4>{faqEntry.question}</h4>
<p>
{faqEntry.answer}
</p>
</div>
{/each}
</section>
The current script works great, allowing me to add FAQ entries directly from the coded form.
Now, I would like to make the FAQ entries list to be refreshed when I submit a new one.
What is the best practice to do this? Also, is my GraphQL implementation done the right way?
You can reuse the preload function to refresh the data:
.then((data) => {
console.log(data);
newEntry.question = '';
newEntry.answer = '';
preload().then(props => {
faqEntries = props.faqEntries
})
The approach is useful when you want to show entries that other users have added at the cost of making extra api calls.
But if you only want to add the recently added entry:
.then((data) => {
faqEntries = [...faqEntries, {...newEntry}]

Resources