now in a simple example in react-rangeslider as below
import React, { Component } from 'react'
import Slider from 'react-rangeslider'
class VolumeSlider extends Component {
constructor(props, context) {
super(props, context)
this.state = {
volume: 0
}
}
handleOnChange = (value) => {
this.setState({
volume: value
})
}
render() {
let { volume } = this.state
return (
<Slider
value={volume}
orientation="vertical"
onChange={this.handleOnChange}
/>
)
}
}
if i change this into a stateless component
return (
<Slider
value={props.volume}
orientation="vertical"
onChange={props.handleOnChange}
/>
)
and i am handling my state and onChange method in a different state-full component how to i pass the value to the handleOnChange method ?
handleOnChange = (value) => {
this.setState({
volume: value
})
}
that's the library i am using
https://www.npmjs.com/package/react-rangeslider
you can do something like this and pass the function and the state from the another component as props.
import React, { Component } from "react";
import Slider from "react-rangeslider";
const VolumeSlider = ({onChange,value}) => {
return <Slider value={value} orientation="vertical" onChange={onChange}/>;
};
Related
I'm successfully passing a React ref through a factory function and down the component hierarchy to a child component that renders a <canvas>. For the factory function, I'm using forwardRef to pass the ref to the created component.
The following works as I can see the simple green rectangle in the browser, rendered by the child component ObservationPlotCanvas
App.jsx
import { createRef, Component } from 'react'
import ObservationPlotFactory from './ObservationPlotFactory'
class App extends Component {
constructor(props) {
super(props)
this.canvasRef = createRef()
}
render() {
const factory = ObservationPlotFactory({ config: { something: true } })
return (
<div className="App">
<header className="App-header"></header>
<factory.Component ref={this.canvasRef} />
</div>
)
}
}
export default App
ObservationPlotFactory.jsx
import React from 'react'
import ObservationPlot from './ObservationPlot'
const ObservationPlotFactory = config => {
return {
Component: forwardRef((props, ref) => {
// do something with config ...
return <ObservationPlot ref={ref} {...props} />
}),
Key: props => {
return <div>Key</div>
},
}
}
export default ObservationPlotFactory
ObservationPlot.jsx
import React, { forwardRef, Component } from 'react'
import ObservationPlotCanvas from './ObservationPlotCanvas'
export class ObservationPlot extends Component {
render() {
return <ObservationPlotCanvas ref={this.props.innerRef} />
}
}
export default forwardRef((props, ref) => <ObservationPlot innerRef={ref} {...props} />)
ObservationPlotCanvas.jsx
import React, { forwardRef, Component } from 'react'
class ObservationPlotCanvas extends Component {
componentDidMount() {
this.draw()
}
componentDidUpdate() {
this.draw()
}
render() {
return (
<div
style={{
position: 'absolute',
top: `100px`,
left: `100px`,
}}
>
<canvas width="600" height="400" ref={this.props.innerRef} />
</div>
)
}
draw() {
if (!this.props?.innerRef?.current) {
return
}
const g = this.props.innerRef.current.getContext('2d')
g.fillStyle = 'green'
g.fillRect(10, 10, 150, 100)
}
}
export default forwardRef((props, ref) => <ObservationPlotCanvas innerRef={ref} {...props} />)
But in the root level App, these components are rendered as a list using map and need to be created dynamically. I'm aware of Callback Refs and normally I would do something like this in the App constructor:
this.canvasRef = []
this.setCanvasRef = index => element => {
this.canvasRef[index] = element;
}
and then:
ref={(el) => this.setCanvasRef(index)}
on the element of interest in the render. But doing this provides the callback function when the child looks at this.props.innerRef and it needs the actual element to reference for it's canvas drawing.
I am using the react-screen-keyboard library and there is the following code example:
import React, {Component, PropTypes} from 'react';
import Keyboard, {KeyboardButton} from 'react-screen-keyboard';
export default class Input extends Component {
static propTypes = {
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func,
}
static defaultProps = {
value: '',
onFocus: null,
}
state = {
inputNode: null,
}
handleInput = (event) => this.props.onChange(event.target.value)
handleFocus = () => {
if (this.props.onFocus) {
this.props.onFocus(this.input);
this.setState({inputNode: this.input});
// the `this.refs.input` value should be passed to the Keyboard component as inputNode prop
}
}
render() {
const {value} = this.props;
const {inputNode} = this.state;
return (
<div>
<input
onInput={this.handleInput}
value={value}
onFocus={this.handleFocus}
ref={(input) => { this.input = input; }}
/>
<Keyboard
inputNode={inputNode}
rightButtons={[
<ClickOnKeyPressWrap key="enter">
<KeyboardButton
onClick={this.handleLoginUser}
value="Войти"
classes="keyboard-submit-button"
/>
</ClickOnKeyPressWrap>
]}
/>
</div>
);
}
}
however, I haven't worked with React class components, and the PropTypes approach has long been deprecated. Tell me, how can I rewrite this example on a functional component?
I am having an issue where I'm trying to pass a function(updateEvents) via props from my App.js file to a NumberOfEvents.js file. I passed the same function to another component with no issues. However, when I try on the NumberOfEvents file, I get the following error:
Error image
Please help!!!
Here is the Parent:
import React, { Component } from 'react';
import EventList from './EventList';
import CitySearch from './CitySearch';
import NumberOfEvents from './NumberOfEvents';
import { extractLocations, getEvents } from './api';
import './nprogress.css';
import './App.css';
class App extends Component {
state = {
events: [],
locations: [],
numberOfEvents: 32
}
componentDidMount() {
this.mounted = true;
getEvents().then((events) => {
if (this.mounted) {
this.setState({
events: events.slice(0, this.state.numberOfEvents),
locations: extractLocations(events)
});
}
});
}
componentWillUnmount() {
this.mounted = false;
}
updateEvents = (location, eventCount) => {
this.mounted = true;
getEvents().then((events) => {
const locationEvents = (location === 'all')
? events
: events.filter((event) => event.location === location);
this.setState({
events: locationEvents,
numberOfEvents: eventCount,
});
});
};
render() {
return (
<div className="App">
<CitySearch
locations={this.state.locations} updateEvents={this.updateEvents} />
<EventList
events={this.state.events} />
<NumberOfEvents
numberOfEvents={this.state.numberOfEvents}
updateEvents={this.updateEvents} />
</div>
);
}
}
export default App;
And here is the Child:
import React, { Component } from 'react';
class NumberOfEvents extends Component {
state = {
numberOfEvents: 32
}
handleChange = (event) => {
const value = event.target.value;
this.setState({
numberOfEvents: value,
});
this.props.updateEvents('', value);
};
render() {
return (
<input
className="number"
value={this.state.numberOfEvents}
onChange={this.handleChange} />
)
}
}
export default NumberOfEvents;
Im not sure this will help ...In Your Parent Component , inside return statement when passing the updateEvents Prop, try passing it as arrow function like this ....
updateEvents={ () => this.updateEvents() } />
try adding a constructor to the child component
constructor(props) {
super(props);
this.state = {
numberOfEvents: 32
}
}
How can I pass a function from FUNCTIONAL to CLASS component using context in react js?
My code:
CONTEXT:
authContext.js
import React from 'react'
const AuthContext = React.createContext()
export const AuthProvider = AuthContext.Provider
export const AuthConsumer = AuthContext.Consumer
export default AuthContext
FUNCTIONAL component:
App.js
...
import AuthPage from './pages/AuthPage';
import { AuthProvider } from './components/Context/authContext'
function App(props) {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const checkAuthenticated = async () => {
//console.time('fetch')
try {
const res = await fetch("http://localhost:4000/api/verify", {
method: "POST",
headers: { jwt_token: localStorage.token }
});
const parseRes = await res.json();
parseRes === true ? setIsAuthenticated(true) : setIsAuthenticated(false);
} catch (err) {
console.error(err.message);
}
//console.timeEnd('fetch')
};
const setAuth = boolean => {
setIsAuthenticated(boolean);
};
useEffect(() => {
checkAuthenticated();
}, [isAuthenticated, setAuth]);
return (
<Fragment>
<BrowserRouter basename={'/'}>
<GAListener>
<Switch>
<LayoutRoute
exact
path="/login"
layout={EmptyLayout}
component={props => (
<AuthProvider value={{ setAuth: setAuth }}>
<AuthPage {...props} authState={STATE_LOGIN} />
</AuthProvider>
)}
/>
<Redirect to="/" />
</Switch>
</GAListener>
</BrowserRouter>
</Fragment>
)
}
export default App;
CLASS component:
AuthForm.js
import AuthContext from '../components/Context/authContext'
class AuthForm extends React.Component {
constructor(props) {
super(props);
this.state = {
usernameInput: '',
emailInput: '',
passwordInput: '',
confirmPasswordInput: '',
remeberMe: false,
agreeTerms: false,
toDashboard: false
};
}
componentDidMount() {
if (localStorage.token) {
this.setState(() => (
{
toDashboard: true
}
))
}
}
componentDidUpdate() {
**// I WANT TO ACCESS THE 'setAuth' function here**
}
render() {
return (
<div>
//Some code
</div>
);
}
}
export default AuthForm;
Using setAuth function from AuthForm.js (class component), I want to change the value of isAuthenticated in App.js (functional component).
So, basically I want to access setAuth in componentDidUpdate().
Resolved the issue with the help from #gemhar
Changes to be made in AuthForm.js
...
import AuthContext from '../components/Context/authContext'
class AuthForm extends React.Component {
//Add this line
static contextType = AuthContext;
constructor(props) {
super(props);
this.state = {
usernameInput: '',
emailInput: '',
passwordInput: '',
confirmPasswordInput: '',
remeberMe: false,
agreeTerms: false,
toDashboard: false
};
}
componentDidMount() {
if (localStorage.token) {
this.setState(() => (
{
toDashboard: true
}
))
}
}
componentDidUpdate() {
//I can access setAuth here
this.context.setAuth(true)
//or by destructuring
let {setAuth} = this.context;
setAuth(true)
}
render() {
return (
<div>
//Some code
</div>
);
}
}
export default AuthForm;
The most common way to access Context from a class component is via the static contextType. If you need the value from Context outside of render, or in a lifecycle method, you'll use it this way.
import React from "react";
import AuthContext from "./context";
class AuthForm extends React.Component {
constructor(props) {
...
}
static contextType = AuthContext
componentDidUpdate() {
const {setAuth} = this.context
// Access the 'setAuth' function here
}
render() {
return <div>Some code</div>;
}
}
export default AuthForm;
I am trying to render a component with already existing data from state (provided from redux-persist), the data in is state.login.user (i can see it in console.log in the mapStateToProps function that is being called and returns the dataObject : state.login.user but the dataObject is not being updated and because of that componentWillReceiveProps is not being called.
Can you point me to what im doing wrong?
import React from 'react'
import { connect } from 'react-redux'
import { ScrollView, AppRegistry, Component, Text, Image, View, Button, Modal, TouchableOpacity } from 'react-native'
import { GiftedForm, GiftedFormManager } from 'react-native-gifted-form'
// Styles
import styles from './Styles/MyProfileScreenStyles'
class MyProfileScreen extends React.Component {
constructor (props, context) {
const dataObject = {
profile: {
last_name : undefined,
}
}
super(props, context)
this.state = {
form: {
lastName: dataObject.profile.last_name,
tos: false
}
}
}
handleValueChange (values) {
this.setState({form: values})
}
componentWillReceiveProps (newProps) {
console.tron.log("componend will receive")
console.tron.log(newProps)
if (newProps.dataObject) {
this.setState({
dataObject: newProps.dataObject
})
}
}
render () {
const {lastName, tos, gender} = this.state.form
console.log('render', this.state.form)
return (
<View style={styles.container}>
<GiftedForm
formName='signupForm'
openModal={(route) => { this.props.navigator.push(route) }}
onValueChange={this.handleValueChange.bind(this)}
>
<GiftedForm.TextInputWidget
name='lastName'
title='Last name'
placeholder='Last name'
clearButtonMode='while-editing'
value={lastName}
/>
<GiftedForm.HiddenWidget name='tos' value={tos}/>
</GiftedForm>
</View>
)
}
}
const mapStateToProps = (state) => {
if( state.login.user !== null){
console.tron.log("test map state to props")
return {
dataObject: state.login.user
}
}
return {}
}
export default connect(mapStateToProps)(MyProfileScreen)
componentWillReceiveProps is only called when the props are updated after the component has rendered, before the component is re-rendered. You'll want to set the state inside your constructor as the props should already be there.