如何在React类中使用React钩子



作为JS世界的新手,我遇到了一个大麻烦。。。我正在使用反作用挂钩

import { useKeycloak } from '@react-keycloak/web';
import { useCallback } from 'react';
export const useAuthenticatedCallback = (callbackFn) => {
const [keycloak, initialized] = useKeycloak()

const authCallback = useCallback(() => {
// Do nothing while Keycloak is initializing
if (!initialized) {
return
}

// if user is not authenticated redirect to login
if (!keycloak.authenticated) {
return keycloak.login()
}

// otherwise invoke function
return callbackFn()
}, [callbackFn, initialized, keycloak])

return authCallback
}

并且能够在功能内部使用

import React from "react";
import {Grid, Avatar, Chip } from '@material-ui/core';
import { useAuthenticatedCallback } from '../../shared/keycloak/KeycloakOnDemand'
// Tranding function component
function Tranding(props) {
const yourCallback = () => {
// The code you need to be authenticated to run
return yourCallback;
};
const authenticatedCallback = useAuthenticatedCallback(yourCallback);
return (
<Grid container spacing={3}>
<Grid className="text-center" item  sm={12} xs={12} md={2}>
<h4>Trending..</h4>
</Grid>
<Grid item md={10}>
<div className="trending-container">
<button onClick={authenticatedCallback} label="ClickMe"/>

</div>
</Grid>
</Grid>
);
}
// export the component.
export default Tranding;

到目前为止,一切都很好,一切都按要求进行。

现在,我遇到了在react组件类中使用相同钩子的挑战,但未能实现。。有人能为这个问题提供帮助吗?

我试着在这门课上使用

import React from "react";
import {connect} from 'react-redux';
import PostList from "./PostList";
import Grid from '@material-ui/core/Grid';
import Switch from '@material-ui/core/Switch';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import Autocomplete from '@material-ui/lab/Autocomplete';
import { TextField, ButtonGroup, Button  } from '@material-ui/core';
import SaveIcon from '@material-ui/icons/Save';
import TextEditor from './TextEditor';
//import CKTextEditor from '../../shared/CKTextEditor';
import {NotificationContainer, NotificationManager} from 'react-notifications';
import CircularSpinner from '../../shared/CircularSpinner';
import postService from '../../services/PostService';
class Posts extends React.Component {
constructor() {
super()
this.state = {
posts: [],
totalPages: 0,
isLoading: false,
postForm: {
isValidationActive: false,
tradeTypeId: 1,
tradeTypeText: 'Buy',
price: '', priceValid: false,
stopLoss: '', stopLossValid: false,
targetPrice: '', targetPriceValid: false,
targetDate: '', targetDateValid: false,
title: '',
notes: '', notesValid: false
},
analysisForm: {
isValidationActive: false,
title: '', titleValid: false,
notes: '', notesTemp:'', notesValid: false
},      
isTradeCallActive: true,
tradeCallFormValid: false,
analysisFormValid: false,
companyCode: '',
companyValid: false,
postTypes: [],
tradeCallTypes: [],
companies: [],
tradeTypeSelected: 'Buy'
};
this.formRef = null;
this.handleChange = this.handleChange.bind(this);
this.onCompanyCodeChange = this.onCompanyCodeChange.bind(this);
this.handleEditorChange = this.handleEditorChange.bind(this);
this.handleTradeCallSubmit = this.handleTradeCallSubmit.bind(this);
this.handleAnalysisSubmit = this.handleAnalysisSubmit.bind(this);
this.loadFormModel = this.loadFormModel.bind(this);
this.clearTradeCallForm = this.clearTradeCallForm.bind(this);
this.clearAnalysisForm = this.clearAnalysisForm.bind(this);
this.loadPosts = this.loadPosts.bind(this);
}

// handle chnage events for all controls.
handleChange(event) {   
let _postForm = this.state.postForm;
let _isTradeCallActive = this.state.isTradeCallActive; 
let _targetValue = event.target.value; 
let _companyValid = this.state.companyValid;
let _companyCode = this.state.companyCode; 
if(event.target.name === 'TradeCall' || event.target.name === 'Analysis'){           
if(event.target.name === 'Analysis' && event.target.checked) {_isTradeCallActive = false;}
if(event.target.name === 'TradeCall' && event.target.checked) {_isTradeCallActive = true;}
}
if(event.target.name === 'txtCompany') {            
_companyCode = _targetValue;
if (_targetValue.length < 3) { _companyValid = false; }
}
if(event.target.name === 'txtTitle'){
let _analysisForm = this.state.analysisForm;
_analysisForm.titleValid = true; 
_analysisForm.title = _targetValue;
if (_targetValue.length < 10) { _analysisForm.titleValid = false; }
let _analysisFormValid = false;
if(_analysisForm.titleValid && _analysisForm.notesValid) {
_analysisFormValid = true;
}

this.setState({ ...this.state, analysisForm: _analysisForm, analysisFormValid: _analysisFormValid});
return;
}
if(event.target.name === 'txtPrice'
|| event.target.name === 'txtStoploss'
|| event.target.name === 'txtTarget'
|| event.target.name === 'notesTextArea'
|| event.target.name === 'targetDate'
|| event.target.name === 'selectTradeType'){

if(event.target.name === 'txtPrice') {
_postForm.priceValid = true;
_postForm.price = _targetValue;
if (_targetValue.length < 1 || _targetValue < 1) { _postForm.priceValid = false; }
}
if(event.target.name === 'txtStoploss') {
_postForm.stopLossValid = true;
_postForm.stopLoss = _targetValue;
if (_targetValue.length < 1 || _targetValue < 1) { _postForm.stopLossValid = false; }
}
if(event.target.name === 'txtTarget') {
_postForm.targetPriceValid = true;
_postForm.targetPrice = _targetValue;
if (_targetValue.length < 1 || _targetValue < 1) { _postForm.targetPriceValid = false; }
}
if(event.target.name === 'notesTextArea') {
_postForm.notesValid = true; 
_postForm.notes = _targetValue;
if (_targetValue.length < 20) { _postForm.notesValid = false; }
}
if(event.target.name === 'targetDate') {
_postForm.targetDateValid = true; 
_postForm.targetDate = _targetValue;
if (_targetValue.length < 8) { _postForm.targetDateValid = false; }
}
}
let _tradeType = this.state.tradeCallTypes.find(x => x.Name === this.state.tradeTypeSelected)
_postForm.tradeTypeId = _tradeType.Id;
_postForm.tradeTypeText = _tradeType.Name; 

let _tradeCallFormValid = false;
if(this.state.companyValid && _postForm.priceValid && _postForm.stopLossValid && _postForm.targetPriceValid && _postForm.targetDateValid && _postForm.notesValid) {
_tradeCallFormValid = true;
_postForm.title = `${_postForm.tradeTypeText} ${this.state.companyCode} at price ${_postForm.price} for target ${_postForm.targetPrice} by date ${_postForm.targetDate} with SL ${_postForm.stopLoss}`; 
}
this.setState({ ...this.state, postForm: _postForm, tradeCallFormValid: _tradeCallFormValid, isTradeCallActive: _isTradeCallActive, companyValid: _companyValid, companyCode: _companyCode });
};


// handle trade call submit click.
handleTradeCallSubmit(){

if(this.state.tradeCallFormValid){
// To DO
this.setState({ ...this.state, tradeCallFormValid: false});
let _postForm = this.state.postForm;
let _companyCode = this.state.companyCode;
let requestBody = {
eventType:'create-trade-call-post', 
callType:_postForm.tradeTypeId,
symbol:_companyCode,
userId: this.props.activeUser.Id,
price:_postForm.price,
stopLoss:_postForm.stopLoss,
targetPrice:_postForm.targetPrice,
targetDate:_postForm.targetDate,
tags: _companyCode,
title:_postForm.title,
notes:_postForm.notes
}

postService.create(requestBody)
.then((result) => {
NotificationManager.success(`Trade call post created successfully...`);
this.loadPosts(1);
this.clearTradeCallForm();
}).catch((error) => {
NotificationManager.error(`Trade call post creation failed..`);
console.log(`Error: ${error}`);
});
} else {
let _postForm = this.state.postForm;
_postForm.isValidationActive = true;
this.setState({ ...this.state, postForm: _postForm});
}

}

// component did mount event called after the virtual DOM loaded. 
componentDidMount() {
this.setState({ ...this.state, isLoading: true });
this.loadFormModel();
}
render() {
if (this.state.isLoading) {
return <CircularSpinner />;
}
return ( 
<div>
<NotificationContainer/>
<Card>
<CardContent>
<form ref={(ref) => this.formRef = ref} noValidate autoComplete="off">
<Grid className="text-center" container spacing={2}>
{
this.state.postTypes.map((postType, index) => 
<Grid key={postType.Id} item sm={6} xs={6} md={3}>
<h5>{postType.Name} <Switch  key={postType.Id}  checked={(postType.Name === 'TradeCall')?this.state.isTradeCallActive: !this.state.isTradeCallActive} value={postType.Id} onChange={this.handleChange} name={postType.Name} inputProps={(postType.Name === 'TradeCall') ? {'aria-label': 'secondary checkbox' }: { 'aria-label': 'primary checkbox' }} /></h5>
</Grid>
)                            
}
<Grid item sm={12} xs={12} md={6}>
<Autocomplete
id="companyAutocomplete"
options={this.state.companies}
getOptionLabel={(option) => option.Symbol}
onInputChange={this.onCompanyCodeChange}  
fullWidth
renderInput={(params) => <TextField fullWidth id="txtCompany" {...params} 
error={((this.state.postForm.isValidationActive || this.state.analysisForm.isValidationActive)) 
&& !this.state.companyValid} name="txtCompany" size="small" label="Company" onChange={this.handleChange} variant="outlined" placeholder="Company.."  />}
/>
</Grid>
</Grid>
<div className={!this.state.isTradeCallActive ? 'hidden' : ''}>
<Grid container spacing={2}>
<Grid item sm={12} xs={12} md={2}>
<ButtonGroup fullWidth aria-label="small button group">
<Button onClick={()=>{this.setState({ ...this.state, tradeTypeSelected: "Sale"})}}
variant={(this.state.tradeTypeSelected === "Buy") ? "outlined" : "contained"} 
color={(this.state.tradeTypeSelected === "Buy") ? "default" : "secondary"}> Sale
</Button>
<Button onClick={()=>{this.setState({ ...this.state, tradeTypeSelected: "Buy"})}} 
variant={(this.state.tradeTypeSelected === "Buy") ? "contained" : "outlined"} 
color={(this.state.tradeTypeSelected === "Buy") ? "secondary" : "default"}> Buy
</Button>
</ButtonGroup>
</Grid>
<Grid item sm={12} xs={12} md={2}>
<TextField fullWidth id="txtPrice" error={this.state.postForm.isValidationActive && !this.state.postForm.priceValid} name="txtPrice" type="number" InputProps={{ inputProps: { min: 0} }} size="small" label="Price" onChange={this.handleChange} variant="outlined" placeholder="Price.."  />
</Grid>
<Grid item sm={12} xs={12} md={2}>
<TextField fullWidth id="txtStoploss" error={this.state.postForm.isValidationActive && !this.state.postForm.stopLossValid} name="txtStoploss" type="number" InputProps={{ inputProps: { min: 0} }}  size="small" label="Stoploss" onChange={this.handleChange} variant="outlined" placeholder="SL.."  />
</Grid>
<Grid item sm={12} xs={12} md={2}>
<TextField fullWidth id="txtTarget" error={this.state.postForm.isValidationActive && !this.state.postForm.targetPriceValid} name="txtTarget" type="number" InputProps={{ inputProps: { min: 0} }}  size="small" label="Target price" onChange={this.handleChange} variant="outlined" placeholder="Price.."  />
</Grid>
<Grid item sm={12} xs={12} md={4}>
<TextField fullWidth id="targetDate" error={this.state.postForm.isValidationActive && !this.state.postForm.targetDateValid} name="targetDate" onChange={this.handleChange} type="date" size="small" label="Target date" variant="outlined"  InputLabelProps={{ shrink: true, }} />
</Grid>
</Grid>
<Grid container spacing={2}>                                
<Grid item sm={12} xs={12} md={12}>
<TextField id="notesTextArea" error={this.state.postForm.isValidationActive && !this.state.postForm.notesValid} name="notesTextArea" onChange={this.handleChange} size="medium" fullWidth 
placeholder="Enter notes here.." variant="outlined" label="Notes"
multiline rows={3} rowsMax={4} />
</Grid>
</Grid>
<Grid justify="center"  container spacing={2}>
<Grid item sm={12} xs={12} md={3}>
<Button size="medium" fullWidth id="btnSubmit" startIcon={<SaveIcon />} onClick={this.handleTradeCallSubmit} variant="contained" color="primary"> Save </Button>
</Grid>
</Grid>
</div>

</form>
</CardContent>
</Card>
<Grid container spacing={3}>
<Grid item md={12}>                    
<PostList totalPages={this.state.totalPages} posts={this.state.posts} loadPosts={this.loadPosts} />
</Grid>
</Grid>
</div>
)
}
} 
// Map redux state to props
const mapStateToProps = state => ({
activeUser: state.session.activeUser
});

// export the component.
export default connect(mapStateToProps)(Posts);

所以在调用handleTradeCallSubmit()方法之前,我想检查用户是否登录,如果不登录,则重定向到登录页面,否则处理该方法?

不能在react class中使用Hook。

挂钩是让您"挂钩"React状态和生命周期的函数功能组件的功能。钩子在类内不起作用--它们允许您在没有类的情况下使用React。(我们不建议重写您的现有组件过夜,但您可以在中开始使用Hooks新的,如果你愿意的话。(

  • https://reactjs.org/docs/hooks-overview.html#:~:text=挂钩%20是%20函数%20它是%20 let,如果%20你喜欢的话。(

虽然use hook不能在类组件内部使用,但hook组件可以在类组件中使用。

因此,一种解决方案是创建一个使用钩子的组件,然后在类中使用该组件。

function AuthenticatedCallback(props) {
const authenticatedCallback = useAuthenticatedCallback(props.callbackFn);
return props.children(authenticatedCallback);
}
//from inside the class component.
......
return (
<AuthenticatedCallback>{authenticatedCallback =>
<Grid container spacing={3}>
<Grid className="text-center" item  sm={12} xs={12} md={2}>
<h4>Trending..</h4>
</Grid>
<Grid item md={10}>
<div className="trending-container">
<button onClick={authenticatedCallback} label="ClickMe"/>
</div>
</Grid>
</Grid>}
</AuthenticatedCallback>
);

请注意,我是如何使用props.children作为函数回调将其传递给组件的。

相关内容

  • 没有找到相关文章

最新更新