Issue in using useFocusEffect inside function component - javascript

I am trying to use "useFocusEffect" inside a functional component and getting the following error:
Couldn't find a navigation object. Is your component inside a screen.
I am using the following approach
useFocusEffect(
React.useCallback(() => {
console.log("Salil RenderFeedContent useFocusEffect ")
}, [])
);
My Component :
export default RenderFeedContent = (props) => {
useFocusEffect(
React.useCallback(() => {
console.log('Salil useFocusEffect RenderFeedContent')
}, [])
);
//Rest of the logic is to render the component .
Code from where the component is getting rendered . This is class based component and I have access to the navigation prop till this point:
const FeedPost=props=>{
const { navigation } = props
return(
<RenderFeedContent {...props} navigation = {navigation} content={props.content} />
)
}
Please refer to following link for all details
Versions:
#react-navigation/native: 5.7.3
#react-navigation/core: 3.7.6
Please help. Am I missing something obvious . I have list of Videos and I want to pause the currently playing video when navigating away from the same. I guess this is because of the version of react navigation I am using .In case more details are required please let me know.

Related

why this setState is not firing?

I'm trying to build a notification React component for my application that I can call from anywhere. I have the below code where I'm trying to do some kinda hack for exporting the showNotif function
function FloatNotification() {
const [show, setShow] = useState(false);
const showNotif = () => {
console.log(`showNotif is called`);
setShow(true);
};
if (!FloatNotification.showNotification) {
FloatNotification.showNotif = showNotif;
}
return <>{show ? `Showing notification` : `not showing notification`}</>
}
export default FloatNotification;
On another file I'm trying to call showNotif like below
import FloatNotification from "./FloatNotification";
function MyComponent() {
const {showNotif} = FloatNotification;
return <><button onClick={() => showNotif()}>Click Me</button></>
}
but the setState isn't getting called unexpectedly. I'm getting the showNotif is called message in the console. so logically the setState should also get called.
I kinda understand it's happening because of how javascript handles reference data type. but I'm not sure what's actually happening behind the scene and how to get my goal
Suggest me if you have any other ideas to build this notification component (something I can call from anywhere in my component tree). Any kind of help will be kudos to me
[NOTE: I'm actually using NextJS and I've added this FloatNotification in the _app.js. So it's available in all the pages
useState is a special function called "hooks". React hooks are only available when the component is rendered in the VDOM tree.
Since you dosen't render FloatNotification as a element, calling setState is unexpected and may has no effects.
There are several ways to achieve what you want without hacking.
First is, lift up notification state to the parent component and inject only the dispatch that changes the state is through the context.
const NotificationContext = React.createContext(() => {});
function FloatNotification({ children }) {
const [show, setShow] = useState(false);
return (
<NotificationContext.Provider value={setShow}>
{children}
<>{show ? `Showing notification` : `not showing notification`}</>
</NotificationContext.Provider>
);
}
function MyComponent() {
const setShow = useContext(NotificaitonContext);
return (
<button onClick={() => setShow(true)}>
Show Notification
</button>
);
}
function App() {
return (
<FloatNotification>
<MyComponent />
</FloatNotification>
);
}
Or, you can exposing the handler by React.useImperativeHandle (commonly not recommended)

Instagram-embed not showing due to height being 0px

Currently I'm using typescript along with react 17.0.2. I made a yarn add react-instagram-embed. I have a component called instagram.tsx where I'm using the following code:
import React from "react";
import InstagramEmbed from "react-instagram-embed";
export default function Instagram({ posts }) {
return (
<div >
<InstagramEmbed
url="https://instagr.am/p/Zw9o4/"
maxWidth={600}
hideCaption={false}
containerTagName="div"
protocol=""
injectScript
onLoading={() => {}}
onSuccess={() => {}}
onAfterRender={() => {}}
onFailure={() => {}}
/>
</div>
);
}
But when I go to my webpage I cannot see the instagram post. I went to inspect element to check out the react developer tools and I could see the correct components:
But when I hover over the components I get
I have tried adding height manually by adding style={{height:"400px"}} in the parent component and maxHeight in the instagramEmbed component but it still does not show up

React js - div onClick link to page

I'm trying to simulate a link in react js clicking on a div.
This is my code:
function handleClick(myLink){
window.location.href=myLink;
}
and here where I call it:
<Col className="aslink" onClick={handleClick('/path/to/myUrl')}>
<div>...</div>
</Col>
But it goes directly to the URL without clicking, so it starts an infinite loop.
How can I solve it?
Many thanks in advance!
This is because you are calling the function in this part <Col className="aslink" onClick={handleClick('/path/to/myUrl')}> instead of providing reference to it to be used on users click action. What you can do is define it like this:
const handleClick = (myLink) => () => {
window.location.href=myLink;
}
then it will work as you want it.
handclick('your path')
is already running the code. Try
onClick = {() => handlick('your path')}
This will stop it from automatically running
First off, I would recommend using React Router's Link over history.location.href, as it uses the routers history api, using this declarative, accessible navigation instead of history means that you are safe to any changes to the history api in the future.
You can import it like this:
import { Link } from 'react-router-dom'
Secondly, you were calling the handleClick function instead of executing the function.
If you use react-router*(which is most possible - if not - then you should research value of this)* then you can get access to browser-history via react router provider
pass router api to your component
if you use modern react version - use hook useHistory -
const Comp = () => {
const history = useHistory()
const handleRedirect = useCallback((path) => {
return () => {
history.push(path);
}
}, [])
return <div onClick={handleRedirect('path-to-page')}>Navigate</div>
}
export default Comp;
or 2. extract history object from taken props in your component
you can wrap you component by HOC - withRouter.
const Comp = ({history}) => {
const handleRedirect = useCallback((path) => {
return () => {
history.push(path);
}
}, [])
return <div onClick={handleRedirect('path-to-page')}>Navigate</div>
}
export default withRouter(Comp)

Conditional rendering in React Native with global variable

I know this is horrible convention, but I'm trying to quickly conditionally render screens in my React Native app with global variables (so no redux):
App.js:
if (global.clickStatus !== 'clicked') {
return <Screen1 />;
}
return <Screen2 />;
The app begins on Screen1, where there is a button that makes global.clickStatus = 'clicked'. When this is clicked, I want Screen2 to render. The problem is, the global.clickStatus doesn't seem to update on my App.js (even though global.clickStatus is changed, it still renders Screen1.
How can I get it to update?
I believe in <App /> component because it is a function component you can introduce a state if your button is clicked. Then with clicked state you can manipulate which component to show.
Similarly like the following - obviously this is a simplified example:
const App = () => {
const [clicked, setClicked] = useState(false);
return <>
<div onClick={() => setClicked(true)}>Click me</div>
{ clicked ? <Screen2 /> : <Screen1 /> }
</>
}
Suggested read is Using the State Hook.
The app begins on Screen1, where there is a button that makes global.clickStatus = 'clicked'
When you click the button, you did not set any state for App.js component => no re-render action is made.
I just assume the button is in Screen 1. Try code below:
import React from "react";
import "./styles.css";
export default function App() {
// Create a state
const [renderIndex, setRenderIndex] = useState(new Date().getTime())
if (global.clickStatus !== 'clicked') {
// Assume you have a button in Screen1
// Pass a callback function from this component to Screen1
// When button in Screen1 is clicked, call this callback function to update renderIndex => App component will re-render
return <Screen1 callBack={() => setRenderIndex(new Date().getTime())}/>;
}
return <Screen2 />;
}

How to simulate events using React-Redux?

I'm building a desktop app using React and Electron.
Since it's growing fast, I realized I need some kind of state management like Redux to avoid passing many properties between components.
I started reading Redux official documentation but still cannot figure out how to implement it in my case. I'm stuck!
For example, I have a main App component that renders many sub-components. One of them has a button. When clicked, it should dispatch an "event" to the store so the main App can act in consequence. How can I accomplish that?
I cannot find the concept of events and I've hit a wall on how to even start using Redux.
Why events? Because it seems silly to me to dispatch an action and modify app state in this case. I just want to inform the root component to dispatch an action based on a user action.
User interacts with a presentational component that should tell a container component to make an API call or start capturing audio/camera for example.
For what I know up to now, the only way to accomplish this is to mutate state so another component listening for changes detects a special value that means "hey, let's do this", then mutate state again to say "hey, I'm doing this", and when it's done state changes again with "hey, it's done".
Can someone point me in the right direction please?
User interacts with a presentational component that should tell a container component to make an API call or start capturing audio/camera for example.
Perhaps your container component is doing more than it should. Consider a situation where React components do no more than two things:
Display DOM elements based on props
Handle user input (dispatch events)
If you were not using redux and wanted to make an API call when clicking a button, that might look something like:
class App extends Component {
state = { data: {} }
makeAPICall() {
fetch(url).then(data => this.setState({ data }))
}
render() {
<Child
data={this.state.data}
makeAPICall={this.makeAPICall}
/>
}
}
let Child = ({ data, makeAPICall }) => (
<button onClick={makeAPICall}>Call API!</button>
)
The App component is responsible for storing global state and handling events, but we have to pass down that state and App's handlers through the component tree, quite possibly through components that will never themselves use those props.
By adding Redux your application now has a much better place to handle side effects like API calls or turning a camera on. Middleware!
Let this (crappy) illustration help you:
So now instead your App component can be just a normal presentational component like all of the others, simply displaying data based on store props and handling any user input / dispatching actions if need be. Let's update the above example using the thunk middleware
// actions.js
export let makeAPICall = () => {
return dispatch => {
fetch(url).then(data => dispatch({
type: 'API_SUCCESS',
payload: data,
})).catch(error => dispatch({ type: 'API_FAIL', payload: error }))
}
}
// Child.js
import { connect } from 'react-redux'
import { makeAPICall } from './actions'
let Child = ({ dispatch }) => (
<button onClick={() => dispatch(makeAPICall())}>Call API!</button>
)
export default connect()(Child)
Thinking about React applications this way is very powerful. The separation of concerns is very well laid out. Components display stuff and handle events. Middleware takes care of any side effects (if there need to be any) and the store simply is an object that will cause React to re-render in case its data changes.
UPDATE: "The Modal Problem"
React apps may have some global stuff like modals and tooltips. Don't think about the "open modal" event.. think "what is the current modal content?".
A modal setup may look something along these lines:
// modalReducer.js
function reducer (state = null, action) {
if (action.type === 'UPDATE_MODAL') {
return action.payload
}
// return default state
return state
}
// App.js
let App = connect(state => ({ modal: state.modal }))(
props =>
<div>
<OtherStuff />
<Modal component={props.modal} />
</div>
)
// Modal.js
let Modal = props =>
<div
style={{
position: 'fixed',
width: '100vw', height: '100vh',
opacity: props.component ? 1 : 0,
}}
>
{props.component}
</div>
// Child.js
let Child = connect()(props =>
<button onClick={e =>
dispatch({
type: 'UPDATE_MODAL'
payload: <YourAwesomeModal />
})
}>
Open your awesome modal!
</button>
)
This is just an example, but would work great! when state.modal is null your Modal has 0 opacity and won't show. When you dispatch UPDATE_MODAL and pass in a component, the modal will show whatever you dispatch and change the opacity to 1 so you can see it. Later you can dispatch { type: 'UPDATE_MODAL', payload: null } to close the modal.
Hopefully this gives you some things to think about!
Definitely read this answer by Dan. His approach is similar but stored modal "metadata" vs the component itself which lends itself better to Redux fanciness like time travel etc.
Is the reason you think it seems silly because you don't want your presentational components to be redux-aware? If so mapDispatchToProps and bindActionCreators might help tidy things up, for example:
// App.js
import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { someAction } from './actions';
import Button from './Button';
const App = ({ onButtonClick }) => (
<div>
Hello.
<Button onClick={onButtonClick}>Click me.</Button>
</div>
);
export default connect(null, dispatch => {
return bindActionCreators({
onButtonClick: someAction
}, dispatch);
})(App);
// Button.js
import React from 'react';
export default Button = ({ onClick, children }) => <button onClick={onClick}>{children}</button>;
As you can see only the connected container component is aware of the action, the Button (and even the App) are unaware that click triggers an action.
For what it's worth, I had a similar problem (click a button elsewhere in the tree and cause a map to reset its viewport) and solved it with a simple incremental key.
Button dispatches action:
export const RESET_MAP = "RESET_MAP";
export const resetMap = () => {
return {
type: RESET_MAP,
};
};
In reducer:
case RESET_MAP:
return Object.assign({}, state, {
setvar: state.setvar + 1
});
In map:
static getDerivedStateFromProps(newProps, state) {
var newState = null;
if (newProps.setvar !== state.setvar) {
newState = {
setvar: newProps.setvar,
[other magic to reset the viewport]
}
}
return newState;

Categories