繁体   English   中英

将 React Context API Class 转换为 Hook 的函数

[英]Convert React Context API Class to function of Hook

如何更改此类基础 Context API 以到达 Hook,而无需更改已使用它的其他组件? 我是新来的反应和整夜,我被卡住了。

实际代码不止这些,但为了简单起见,我试图删除一些代码:

import React, { createContext, Component } from 'react'
 
const MainContext = createContext();

class MainContextProvider extends Component {

     state = {
        isLogin : false,
        loginData : [],
        spinner : false
     }                  
   
handleUserLogin  = (res) => {   
  this.setState({ 
      ...this.state,
      isLogin   : res.isLogin,
      loginData : res.data
   })        
}

showSpinner = (status) => {
   this.setState({ 
     ...this.state,
     spinner : status
   })           
}

    
 render() { 
    
   console.log(this.state)

    return (   
      <MainContext.Provider value = {{        
         
           ...this.state,
           showSpinner : this.showSpinner,
           handleUserLogin : this.handleUserLogin,
          }}>

      {this.props.children}

      </MainContext.Provider>
    );
  }
}

const MainContextConsumer = MainContext.Consumer; 
export {MainContextProvider,  MainContextConsumer, MainContext};

我用这个 MainContextProvider 包装 index.js 以便所有组件都可以使用状态或使用方法。

以下是如何使用带有钩子的context并保持与现有 API 相同的 API:

import React, { createContext, useContext, useState } from "react";
import "./style.css";

// Define your context, this is the same
const MainContext = createContext();

function Provider({ children }) {

  // Define some state to hold the data
  let [state, setState] = useState({
    isLogin: false,
    loginData: [],
    spinner: false
  });
  
  // Define a few functions that change the state
  let handleUserLogin = res => {
    setState(s => ({
      ...s,
      isLogin: res.isLogin,
      loginData: res.data
    }));
  };

  // Define a few functions that change the state
  let showSpinner = status => {
    setState(s => ({ ...s, spinner: status }));
  };

  // Pass the `state` and `functions` to the context value
  return (
    <MainContext.Provider
      value={{ ...state, handleUserLogin, showSpinner }}
    >
      {children}
    </MainContext.Provider>
  );
}

function Stuff() {
  // Inside your component use the context with `useContext` hook
  let { showSpinner, handleUserLogin, ...state  } = useContext(MainContext);
  return (
    <div>
      <div>
        <code>{JSON.stringify(state, null, 2)}</code>
      </div>

      <button onClick={() => showSpinner(Math.random())}>
        Show Spinner
      </button>
    </div>
  );
}

export default function App() {
  return (
    <Provider>
      <Stuff />
    </Provider>
  );
}

查看StackBlitz 上演示

作为 Sam R. 的建议,我几乎没有修改并按预期工作。 也许使用 Reducer 更好,但我不喜欢。 而且我认为 Context API 比 Redux 更简单。

主上下文.js :

import React, { createContext, useState } from 'react'
 
const MainContext = createContext();

const MainContextProvider = ({ children }) => {

  // Define some state to hold the data
  let [state, setState] = useState({
    isLogin: false,
    loginData: [],
    spinner: false
  });
  
  // Define a few functions that change the state
  let handleUserLogin = res => {
    setState(s => ({
      ...s,
      isLogin: res.isLogin,
      loginData: res.data
    }));
  };

  // Define a few functions that change the state
  let showSpinner = status => {
    setState(s => ({ ...s, spinner: status }));
  };

  // Pass the `state` and `functions` to the context value
  return (
    <MainContext.Provider
      value={{ ...state, handleUserLogin, showSpinner }}
    >
      {children}
    </MainContext.Provider>
  );
}

const MainContextConsumer = MainContext.Consumer; 
export {MainContextProvider,  MainContextConsumer, MainContext};

登录.js:

import React, { useState, useContext } from "react";
import { Link } from "react-router-dom";
import { useHistory } from "react-router-dom";

import {MainContext} from "../contextApi/MainContext";
import { login } from "../api/Api_User";


const Login = () => {
  const history = useHistory();
    
  const { handleUserLogin, showSpinner } = useContext(MainContext);

  const [user , setUser] = useState({ email : "", password : "" })
  const [errors , setErrors] = useState({ emailErr : "", passErr : "" })
  
  
  const handleChange = e => {   
      const {name , value} = e.target    
      setUser( prevState => ({ ...prevState,[name] : value }))  
      setErrors({ emailErr : "", passErr : "" });   
  }
  
  const handleSubmit = (e) => { 
  
       // client side validation      
       if(!user.email)    { setErrors({ emailErr : "Please enter email" }); return false; }
       if(!user.password) { setErrors({ passErr : "Please enter password" }); return false; }
      
      
      showSpinner(true)

      const data = {
        email: user.email,
        password: user.password 
      }
      
       // axios call
       login(data).then(res => {
              
        setTimeout(() => {
            
            showSpinner(false)
            
            if (res) {
              if (res.status === true) {
               localStorage.setItem("token", res.token); // jwt token from server
               handleUserLogin(res) // store server respond to global states
               return history.push('/dashboard')
              }
               
              // server side validation
               if (res.status === false) {  
                 res.path === 'email' &&  setErrors({ emailErr : res.message }) 
                 res.path === 'password' && setErrors({ passErr : res.message }) 
               }
            }
        
        },100 )
        
        
   });
   }
 


   return (
     <div className="page">
          <div className="page-content mt-5 mb-5">
            <div className="content-sticky-footer">
            
          <div className="container">
            <div className="row">
              <div className="col">
              
                    <div className="card mb-0">
                      <div className="card-header">
                        <h3 className="mx-auto mt-4">LOGIN MEMBER</h3>
                      </div>
                      
                      <div className="card-body">
                          <div className="form-group">
                            <label>Email address *</label>
                            <input
                              type="email" className="form-control"
                               name="email"
                               value={user.email}
                                onChange={handleChange}
                            />
                            <span className="text-danger label-sm ">
                             {errors.emailErr}
                           </span>
                          </div>

                          <div className="form-group">
                            <label>Password *</label>
                            <input
                              type="password" className="form-control"
                               name="password"
                              value={user.password}
                              onChange={handleChange}
                            />
                            <span className="text-danger label-sm ">
                             {errors.passErr}
                           </span>
                          </div>
                         
                          <div className="form-footer mt-2">
                            <button
                              type="button"
                              className="btn btn-primary btn-block btn-lg btn-submit"
                              onClick={handleSubmit}
                             >
                              Login
                            </button>
                          </div>

                          <div className="text-center mt-3 text-dark">
                            Do not have account?
                            <Link to="/register"> Register</Link>
                          </div>

                      </div>
                    </div>
                  </div>
                </div>
          </div>
         </div>
     </div>
     </div>
   );

}

export default Login

索引.js :

import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import './css/App.css';
import App from './App';

import { BrowserRouter} from "react-router-dom";
import {MainContextProvider} from './contextApi/MainContext';  

import axios from "axios";

 // express server with mongodb
 axios.defaults.baseURL = "http://localhost:3001"; 
 
ReactDOM.render(
    <MainContextProvider>
      <BrowserRouter>
            <App />
          </BrowserRouter>
     </MainContextProvider>,
  document.getElementById('root')
);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM