How to use React hook in a react class?

六月ゝ 毕业季﹏ 提交于 2021-02-10 20:00:21

问题


As a newbie in JS world i am in a big trouble ... I am using a react hook

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
  }

and able to use inside a function

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;

Upto here everything fine and things are working according to requirement.

Now i got a challenge to use same hook inside a react component class ,but fail to achieve this ..Can anyone help for this issue?

I was trying to use in this class

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);

So before calling handleTradeCallSubmit() method i want to check user is login or not if not login redirect to login page otherwise process the method?


回答1:


Although use hooks cannot be used inside a class component, hook components can be used inside a class component.

So one solution is to create a component that uses the hook, and then use the component inside the class instead.

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>
);

Notice how I'm using the props.children as a functional callback to pass this down to the component.




回答2:


You can not use a Hook inside a react Class.

Hooks are functions that let you “hook into” React state and lifecycle features from function components. Hooks don’t work inside classes — they let you use React without classes. (We don’t recommend rewriting your existing components overnight but you can start using Hooks in the new ones if you’d like.)

  • https://reactjs.org/docs/hooks-overview.html#:~:text=Hooks%20are%20functions%20that%20let,if%20you'd%20like.)


来源:https://stackoverflow.com/questions/63525070/how-to-use-react-hook-in-a-react-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!